From a2b3e8b74d1729d48ee89f8b0846bd3449484c83 Mon Sep 17 00:00:00 2001 From: John Doty Date: Sun, 7 Apr 2024 07:00:02 -0700 Subject: [PATCH] [fine] Remove salsa dependency --- Cargo.lock | 109 - fine/Cargo.toml | 1 - .../vendor/arc-swap/.cargo-checksum.json | 1 - third-party/vendor/arc-swap/CHANGELOG.md | 232 -- third-party/vendor/arc-swap/Cargo.toml | 91 - third-party/vendor/arc-swap/LICENSE-APACHE | 201 -- third-party/vendor/arc-swap/LICENSE-MIT | 25 - third-party/vendor/arc-swap/README.md | 41 - third-party/vendor/arc-swap/TODO | 1 - .../vendor/arc-swap/benches/background.rs | 335 --- .../vendor/arc-swap/benches/int-access.rs | 130 - third-party/vendor/arc-swap/benches/track.rs | 113 - third-party/vendor/arc-swap/ci-check.sh | 16 - third-party/vendor/arc-swap/rustfmt.toml | 0 third-party/vendor/arc-swap/src/access.rs | 546 ---- third-party/vendor/arc-swap/src/as_raw.rs | 72 - third-party/vendor/arc-swap/src/cache.rs | 343 --- .../vendor/arc-swap/src/compile_fail_tests.rs | 93 - third-party/vendor/arc-swap/src/debt/fast.rs | 76 - .../vendor/arc-swap/src/debt/helping.rs | 334 --- third-party/vendor/arc-swap/src/debt/list.rs | 371 --- third-party/vendor/arc-swap/src/debt/mod.rs | 137 - .../vendor/arc-swap/src/docs/internal.rs | 106 - .../vendor/arc-swap/src/docs/limitations.rs | 53 - third-party/vendor/arc-swap/src/docs/mod.rs | 54 - .../vendor/arc-swap/src/docs/patterns.rs | 271 -- .../vendor/arc-swap/src/docs/performance.rs | 87 - third-party/vendor/arc-swap/src/lib.rs | 1317 ---------- third-party/vendor/arc-swap/src/ref_cnt.rs | 176 -- third-party/vendor/arc-swap/src/serde.rs | 132 - .../vendor/arc-swap/src/strategy/hybrid.rs | 235 -- .../vendor/arc-swap/src/strategy/mod.rs | 168 -- .../vendor/arc-swap/src/strategy/rw_lock.rs | 63 - .../arc-swap/src/strategy/test_strategies.rs | 22 - third-party/vendor/arc-swap/src/weak.rs | 118 - third-party/vendor/arc-swap/tests/random.rs | 125 - third-party/vendor/arc-swap/tests/stress.rs | 310 --- .../crossbeam-deque/.cargo-checksum.json | 1 - .../vendor/crossbeam-deque/CHANGELOG.md | 137 - third-party/vendor/crossbeam-deque/Cargo.toml | 50 - .../vendor/crossbeam-deque/LICENSE-APACHE | 201 -- .../vendor/crossbeam-deque/LICENSE-MIT | 27 - third-party/vendor/crossbeam-deque/README.md | 46 - .../vendor/crossbeam-deque/src/deque.rs | 2201 ----------------- third-party/vendor/crossbeam-deque/src/lib.rs | 103 - .../vendor/crossbeam-deque/tests/fifo.rs | 357 --- .../vendor/crossbeam-deque/tests/injector.rs | 375 --- .../vendor/crossbeam-deque/tests/lifo.rs | 359 --- .../vendor/crossbeam-deque/tests/steal.rs | 212 -- .../crossbeam-epoch/.cargo-checksum.json | 1 - .../vendor/crossbeam-epoch/CHANGELOG.md | 204 -- third-party/vendor/crossbeam-epoch/Cargo.lock | 457 ---- third-party/vendor/crossbeam-epoch/Cargo.toml | 57 - .../vendor/crossbeam-epoch/LICENSE-APACHE | 201 -- .../vendor/crossbeam-epoch/LICENSE-MIT | 27 - third-party/vendor/crossbeam-epoch/README.md | 53 - .../vendor/crossbeam-epoch/benches/defer.rs | 69 - .../vendor/crossbeam-epoch/benches/flush.rs | 52 - .../vendor/crossbeam-epoch/benches/pin.rs | 31 - .../crossbeam-epoch/examples/sanitize.rs | 66 - .../vendor/crossbeam-epoch/src/atomic.rs | 1702 ------------- .../vendor/crossbeam-epoch/src/collector.rs | 464 ---- .../vendor/crossbeam-epoch/src/default.rs | 93 - .../vendor/crossbeam-epoch/src/deferred.rs | 146 -- .../vendor/crossbeam-epoch/src/epoch.rs | 132 - .../vendor/crossbeam-epoch/src/guard.rs | 523 ---- .../vendor/crossbeam-epoch/src/internal.rs | 600 ----- third-party/vendor/crossbeam-epoch/src/lib.rs | 166 -- .../vendor/crossbeam-epoch/src/sync/list.rs | 487 ---- .../vendor/crossbeam-epoch/src/sync/mod.rs | 7 - .../crossbeam-epoch/src/sync/once_lock.rs | 88 - .../vendor/crossbeam-epoch/src/sync/queue.rs | 468 ---- .../vendor/crossbeam-epoch/tests/loom.rs | 157 -- .../crossbeam-queue/.cargo-checksum.json | 1 - .../vendor/crossbeam-queue/CHANGELOG.md | 84 - third-party/vendor/crossbeam-queue/Cargo.toml | 49 - .../vendor/crossbeam-queue/LICENSE-APACHE | 201 -- .../vendor/crossbeam-queue/LICENSE-MIT | 27 - third-party/vendor/crossbeam-queue/README.md | 54 - .../vendor/crossbeam-queue/src/array_queue.rs | 541 ---- third-party/vendor/crossbeam-queue/src/lib.rs | 32 - .../vendor/crossbeam-queue/src/seg_queue.rs | 549 ---- .../crossbeam-queue/tests/array_queue.rs | 374 --- .../vendor/crossbeam-queue/tests/seg_queue.rs | 195 -- .../vendor/crossbeam/.cargo-checksum.json | 1 - third-party/vendor/crossbeam/CHANGELOG.md | 105 - third-party/vendor/crossbeam/Cargo.toml | 86 - third-party/vendor/crossbeam/LICENSE-APACHE | 201 -- third-party/vendor/crossbeam/LICENSE-MIT | 27 - third-party/vendor/crossbeam/README.md | 158 -- third-party/vendor/crossbeam/build-common.rs | 13 - third-party/vendor/crossbeam/no_atomic.rs | 12 - third-party/vendor/crossbeam/src/lib.rs | 81 - .../vendor/crossbeam/tests/subcrates.rs | 48 - third-party/vendor/eyre/.cargo-checksum.json | 1 - third-party/vendor/eyre/CHANGELOG.md | 91 - third-party/vendor/eyre/Cargo.lock | 504 ---- third-party/vendor/eyre/Cargo.toml | 84 - third-party/vendor/eyre/LICENSE-APACHE | 201 -- third-party/vendor/eyre/LICENSE-MIT | 23 - third-party/vendor/eyre/README.md | 269 -- third-party/vendor/eyre/build.rs | 132 - .../vendor/eyre/examples/custom_handler.rs | 81 - .../vendor/eyre/examples/eyre-usage.rs | 7 - third-party/vendor/eyre/src/backtrace.rs | 22 - third-party/vendor/eyre/src/chain.rs | 109 - third-party/vendor/eyre/src/context.rs | 192 -- third-party/vendor/eyre/src/error.rs | 912 ------- .../vendor/eyre/src/error/pyo3_compat.rs | 7 - third-party/vendor/eyre/src/fmt.rs | 21 - third-party/vendor/eyre/src/kind.rs | 111 - third-party/vendor/eyre/src/lib.rs | 1322 ---------- third-party/vendor/eyre/src/macros.rs | 170 -- third-party/vendor/eyre/src/option.rs | 15 - third-party/vendor/eyre/src/ptr.rs | 149 -- third-party/vendor/eyre/src/wrapper.rs | 93 - third-party/vendor/eyre/tests/common/mod.rs | 29 - third-party/vendor/eyre/tests/compiletest.rs | 7 - third-party/vendor/eyre/tests/drop/mod.rs | 55 - .../vendor/eyre/tests/test_autotrait.rs | 13 - third-party/vendor/eyre/tests/test_boxed.rs | 66 - third-party/vendor/eyre/tests/test_chain.rs | 54 - third-party/vendor/eyre/tests/test_context.rs | 173 -- .../vendor/eyre/tests/test_context_access.rs | 13 - third-party/vendor/eyre/tests/test_convert.rs | 28 - .../vendor/eyre/tests/test_downcast.rs | 148 -- third-party/vendor/eyre/tests/test_fmt.rs | 105 - .../vendor/eyre/tests/test_location.rs | 183 -- third-party/vendor/eyre/tests/test_macros.rs | 102 - .../vendor/eyre/tests/test_no_install.rs | 18 - third-party/vendor/eyre/tests/test_option.rs | 15 - third-party/vendor/eyre/tests/test_pyo3.rs | 33 - third-party/vendor/eyre/tests/test_repr.rs | 36 - third-party/vendor/eyre/tests/test_source.rs | 75 - .../vendor/eyre/tests/test_toolchain.rs | 34 - .../vendor/hashlink/.cargo-checksum.json | 1 - third-party/vendor/hashlink/CHANGELOG.md | 81 - third-party/vendor/hashlink/Cargo.toml | 46 - third-party/vendor/hashlink/LICENSE-APACHE | 201 -- third-party/vendor/hashlink/LICENSE-MIT | 26 - third-party/vendor/hashlink/README.md | 67 - third-party/vendor/hashlink/src/lib.rs | 12 - .../vendor/hashlink/src/linked_hash_map.rs | 2180 ---------------- .../vendor/hashlink/src/linked_hash_set.rs | 766 ------ third-party/vendor/hashlink/src/lru_cache.rs | 292 --- third-party/vendor/hashlink/src/serde.rs | 161 -- .../vendor/hashlink/tests/linked_hash_map.rs | 563 ----- .../vendor/hashlink/tests/linked_hash_set.rs | 543 ---- .../vendor/hashlink/tests/lru_cache.rs | 166 -- third-party/vendor/hashlink/tests/serde.rs | 110 - third-party/vendor/heck/.cargo-checksum.json | 1 - third-party/vendor/heck/CHANGELOG.md | 17 - third-party/vendor/heck/Cargo.toml | 43 - third-party/vendor/heck/LICENSE-APACHE | 201 -- third-party/vendor/heck/LICENSE-MIT | 25 - third-party/vendor/heck/README.md | 64 - third-party/vendor/heck/src/kebab.rs | 70 - third-party/vendor/heck/src/lib.rs | 209 -- third-party/vendor/heck/src/lower_camel.rs | 85 - third-party/vendor/heck/src/shouty_kebab.rs | 72 - third-party/vendor/heck/src/shouty_snake.rs | 85 - third-party/vendor/heck/src/snake.rs | 98 - third-party/vendor/heck/src/title.rs | 71 - third-party/vendor/heck/src/train.rs | 85 - third-party/vendor/heck/src/upper_camel.rs | 84 - .../vendor/indenter/.cargo-checksum.json | 1 - third-party/vendor/indenter/CHANGELOG.md | 31 - third-party/vendor/indenter/Cargo.lock | 5 - third-party/vendor/indenter/Cargo.toml | 70 - third-party/vendor/indenter/README.md | 113 - third-party/vendor/indenter/examples/usage.rs | 12 - third-party/vendor/indenter/src/lib.rs | 542 ---- .../salsa-2022-macros/.cargo-checksum.json | 1 - .../vendor/salsa-2022-macros/Cargo.toml | 32 - .../salsa-2022-macros/src/accumulator.rs | 162 -- .../salsa-2022-macros/src/configuration.rs | 94 - .../vendor/salsa-2022-macros/src/db.rs | 233 -- .../vendor/salsa-2022-macros/src/input.rs | 321 --- .../vendor/salsa-2022-macros/src/interned.rs | 195 -- .../vendor/salsa-2022-macros/src/jar.rs | 172 -- .../vendor/salsa-2022-macros/src/lib.rs | 73 - .../vendor/salsa-2022-macros/src/options.rs | 280 --- .../salsa-2022-macros/src/salsa_struct.rs | 472 ---- .../vendor/salsa-2022-macros/src/tracked.rs | 21 - .../salsa-2022-macros/src/tracked_fn.rs | 893 ------- .../salsa-2022-macros/src/tracked_struct.rs | 324 --- .../vendor/salsa-2022/.cargo-checksum.json | 1 - third-party/vendor/salsa-2022/Cargo.toml | 33 - .../vendor/salsa-2022/src/accumulator.rs | 172 -- .../vendor/salsa-2022/src/cancelled.rs | 57 - third-party/vendor/salsa-2022/src/cycle.rs | 125 - third-party/vendor/salsa-2022/src/database.rs | 138 -- third-party/vendor/salsa-2022/src/debug.rs | 247 -- .../vendor/salsa-2022/src/durability.rs | 49 - third-party/vendor/salsa-2022/src/event.rs | 221 -- third-party/vendor/salsa-2022/src/function.rs | 290 --- .../salsa-2022/src/function/accumulated.rs | 79 - .../salsa-2022/src/function/backdate.rs | 36 - .../vendor/salsa-2022/src/function/delete.rs | 20 - .../salsa-2022/src/function/diff_outputs.rs | 52 - .../vendor/salsa-2022/src/function/execute.rs | 112 - .../vendor/salsa-2022/src/function/fetch.rs | 93 - .../vendor/salsa-2022/src/function/inputs.rs | 12 - .../vendor/salsa-2022/src/function/lru.rs | 38 - .../src/function/maybe_changed_after.rs | 223 -- .../vendor/salsa-2022/src/function/memo.rs | 135 - .../vendor/salsa-2022/src/function/specify.rs | 141 -- .../vendor/salsa-2022/src/function/store.rs | 41 - .../vendor/salsa-2022/src/function/sync.rs | 90 - third-party/vendor/salsa-2022/src/hash.rs | 14 - third-party/vendor/salsa-2022/src/id.rs | 94 - .../vendor/salsa-2022/src/ingredient.rs | 90 - .../vendor/salsa-2022/src/ingredient_list.rs | 83 - third-party/vendor/salsa-2022/src/input.rs | 133 - .../vendor/salsa-2022/src/input_field.rs | 170 -- third-party/vendor/salsa-2022/src/interned.rs | 278 --- third-party/vendor/salsa-2022/src/jar.rs | 24 - third-party/vendor/salsa-2022/src/key.rs | 106 - third-party/vendor/salsa-2022/src/lib.rs | 53 - third-party/vendor/salsa-2022/src/plumbing.rs | 28 - third-party/vendor/salsa-2022/src/revision.rs | 63 - third-party/vendor/salsa-2022/src/routes.rs | 126 - third-party/vendor/salsa-2022/src/runtime.rs | 444 ---- .../salsa-2022/src/runtime/active_query.rs | 147 -- .../src/runtime/dependency_graph.rs | 277 --- .../salsa-2022/src/runtime/local_state.rs | 364 --- .../salsa-2022/src/runtime/shared_state.rs | 56 - .../vendor/salsa-2022/src/salsa_struct.rs | 15 - third-party/vendor/salsa-2022/src/setter.rs | 39 - third-party/vendor/salsa-2022/src/storage.rs | 264 -- .../vendor/salsa-2022/src/tracked_struct.rs | 198 -- 231 files changed, 41310 deletions(-) delete mode 100644 third-party/vendor/arc-swap/.cargo-checksum.json delete mode 100644 third-party/vendor/arc-swap/CHANGELOG.md delete mode 100644 third-party/vendor/arc-swap/Cargo.toml delete mode 100644 third-party/vendor/arc-swap/LICENSE-APACHE delete mode 100644 third-party/vendor/arc-swap/LICENSE-MIT delete mode 100644 third-party/vendor/arc-swap/README.md delete mode 100644 third-party/vendor/arc-swap/TODO delete mode 100644 third-party/vendor/arc-swap/benches/background.rs delete mode 100644 third-party/vendor/arc-swap/benches/int-access.rs delete mode 100644 third-party/vendor/arc-swap/benches/track.rs delete mode 100755 third-party/vendor/arc-swap/ci-check.sh delete mode 100644 third-party/vendor/arc-swap/rustfmt.toml delete mode 100644 third-party/vendor/arc-swap/src/access.rs delete mode 100644 third-party/vendor/arc-swap/src/as_raw.rs delete mode 100644 third-party/vendor/arc-swap/src/cache.rs delete mode 100644 third-party/vendor/arc-swap/src/compile_fail_tests.rs delete mode 100644 third-party/vendor/arc-swap/src/debt/fast.rs delete mode 100644 third-party/vendor/arc-swap/src/debt/helping.rs delete mode 100644 third-party/vendor/arc-swap/src/debt/list.rs delete mode 100644 third-party/vendor/arc-swap/src/debt/mod.rs delete mode 100644 third-party/vendor/arc-swap/src/docs/internal.rs delete mode 100644 third-party/vendor/arc-swap/src/docs/limitations.rs delete mode 100644 third-party/vendor/arc-swap/src/docs/mod.rs delete mode 100644 third-party/vendor/arc-swap/src/docs/patterns.rs delete mode 100644 third-party/vendor/arc-swap/src/docs/performance.rs delete mode 100644 third-party/vendor/arc-swap/src/lib.rs delete mode 100644 third-party/vendor/arc-swap/src/ref_cnt.rs delete mode 100644 third-party/vendor/arc-swap/src/serde.rs delete mode 100644 third-party/vendor/arc-swap/src/strategy/hybrid.rs delete mode 100644 third-party/vendor/arc-swap/src/strategy/mod.rs delete mode 100644 third-party/vendor/arc-swap/src/strategy/rw_lock.rs delete mode 100644 third-party/vendor/arc-swap/src/strategy/test_strategies.rs delete mode 100644 third-party/vendor/arc-swap/src/weak.rs delete mode 100644 third-party/vendor/arc-swap/tests/random.rs delete mode 100644 third-party/vendor/arc-swap/tests/stress.rs delete mode 100644 third-party/vendor/crossbeam-deque/.cargo-checksum.json delete mode 100644 third-party/vendor/crossbeam-deque/CHANGELOG.md delete mode 100644 third-party/vendor/crossbeam-deque/Cargo.toml delete mode 100644 third-party/vendor/crossbeam-deque/LICENSE-APACHE delete mode 100644 third-party/vendor/crossbeam-deque/LICENSE-MIT delete mode 100644 third-party/vendor/crossbeam-deque/README.md delete mode 100644 third-party/vendor/crossbeam-deque/src/deque.rs delete mode 100644 third-party/vendor/crossbeam-deque/src/lib.rs delete mode 100644 third-party/vendor/crossbeam-deque/tests/fifo.rs delete mode 100644 third-party/vendor/crossbeam-deque/tests/injector.rs delete mode 100644 third-party/vendor/crossbeam-deque/tests/lifo.rs delete mode 100644 third-party/vendor/crossbeam-deque/tests/steal.rs delete mode 100644 third-party/vendor/crossbeam-epoch/.cargo-checksum.json delete mode 100644 third-party/vendor/crossbeam-epoch/CHANGELOG.md delete mode 100644 third-party/vendor/crossbeam-epoch/Cargo.lock delete mode 100644 third-party/vendor/crossbeam-epoch/Cargo.toml delete mode 100644 third-party/vendor/crossbeam-epoch/LICENSE-APACHE delete mode 100644 third-party/vendor/crossbeam-epoch/LICENSE-MIT delete mode 100644 third-party/vendor/crossbeam-epoch/README.md delete mode 100644 third-party/vendor/crossbeam-epoch/benches/defer.rs delete mode 100644 third-party/vendor/crossbeam-epoch/benches/flush.rs delete mode 100644 third-party/vendor/crossbeam-epoch/benches/pin.rs delete mode 100644 third-party/vendor/crossbeam-epoch/examples/sanitize.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/atomic.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/collector.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/default.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/deferred.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/epoch.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/guard.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/internal.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/lib.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/sync/list.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/sync/mod.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/sync/once_lock.rs delete mode 100644 third-party/vendor/crossbeam-epoch/src/sync/queue.rs delete mode 100644 third-party/vendor/crossbeam-epoch/tests/loom.rs delete mode 100644 third-party/vendor/crossbeam-queue/.cargo-checksum.json delete mode 100644 third-party/vendor/crossbeam-queue/CHANGELOG.md delete mode 100644 third-party/vendor/crossbeam-queue/Cargo.toml delete mode 100644 third-party/vendor/crossbeam-queue/LICENSE-APACHE delete mode 100644 third-party/vendor/crossbeam-queue/LICENSE-MIT delete mode 100644 third-party/vendor/crossbeam-queue/README.md delete mode 100644 third-party/vendor/crossbeam-queue/src/array_queue.rs delete mode 100644 third-party/vendor/crossbeam-queue/src/lib.rs delete mode 100644 third-party/vendor/crossbeam-queue/src/seg_queue.rs delete mode 100644 third-party/vendor/crossbeam-queue/tests/array_queue.rs delete mode 100644 third-party/vendor/crossbeam-queue/tests/seg_queue.rs delete mode 100644 third-party/vendor/crossbeam/.cargo-checksum.json delete mode 100644 third-party/vendor/crossbeam/CHANGELOG.md delete mode 100644 third-party/vendor/crossbeam/Cargo.toml delete mode 100644 third-party/vendor/crossbeam/LICENSE-APACHE delete mode 100644 third-party/vendor/crossbeam/LICENSE-MIT delete mode 100644 third-party/vendor/crossbeam/README.md delete mode 100644 third-party/vendor/crossbeam/build-common.rs delete mode 100644 third-party/vendor/crossbeam/no_atomic.rs delete mode 100644 third-party/vendor/crossbeam/src/lib.rs delete mode 100644 third-party/vendor/crossbeam/tests/subcrates.rs delete mode 100644 third-party/vendor/eyre/.cargo-checksum.json delete mode 100644 third-party/vendor/eyre/CHANGELOG.md delete mode 100644 third-party/vendor/eyre/Cargo.lock delete mode 100644 third-party/vendor/eyre/Cargo.toml delete mode 100644 third-party/vendor/eyre/LICENSE-APACHE delete mode 100644 third-party/vendor/eyre/LICENSE-MIT delete mode 100644 third-party/vendor/eyre/README.md delete mode 100644 third-party/vendor/eyre/build.rs delete mode 100644 third-party/vendor/eyre/examples/custom_handler.rs delete mode 100644 third-party/vendor/eyre/examples/eyre-usage.rs delete mode 100644 third-party/vendor/eyre/src/backtrace.rs delete mode 100644 third-party/vendor/eyre/src/chain.rs delete mode 100644 third-party/vendor/eyre/src/context.rs delete mode 100644 third-party/vendor/eyre/src/error.rs delete mode 100644 third-party/vendor/eyre/src/error/pyo3_compat.rs delete mode 100644 third-party/vendor/eyre/src/fmt.rs delete mode 100644 third-party/vendor/eyre/src/kind.rs delete mode 100644 third-party/vendor/eyre/src/lib.rs delete mode 100644 third-party/vendor/eyre/src/macros.rs delete mode 100644 third-party/vendor/eyre/src/option.rs delete mode 100644 third-party/vendor/eyre/src/ptr.rs delete mode 100644 third-party/vendor/eyre/src/wrapper.rs delete mode 100644 third-party/vendor/eyre/tests/common/mod.rs delete mode 100644 third-party/vendor/eyre/tests/compiletest.rs delete mode 100644 third-party/vendor/eyre/tests/drop/mod.rs delete mode 100644 third-party/vendor/eyre/tests/test_autotrait.rs delete mode 100644 third-party/vendor/eyre/tests/test_boxed.rs delete mode 100644 third-party/vendor/eyre/tests/test_chain.rs delete mode 100644 third-party/vendor/eyre/tests/test_context.rs delete mode 100644 third-party/vendor/eyre/tests/test_context_access.rs delete mode 100644 third-party/vendor/eyre/tests/test_convert.rs delete mode 100644 third-party/vendor/eyre/tests/test_downcast.rs delete mode 100644 third-party/vendor/eyre/tests/test_fmt.rs delete mode 100644 third-party/vendor/eyre/tests/test_location.rs delete mode 100644 third-party/vendor/eyre/tests/test_macros.rs delete mode 100644 third-party/vendor/eyre/tests/test_no_install.rs delete mode 100644 third-party/vendor/eyre/tests/test_option.rs delete mode 100644 third-party/vendor/eyre/tests/test_pyo3.rs delete mode 100644 third-party/vendor/eyre/tests/test_repr.rs delete mode 100644 third-party/vendor/eyre/tests/test_source.rs delete mode 100644 third-party/vendor/eyre/tests/test_toolchain.rs delete mode 100644 third-party/vendor/hashlink/.cargo-checksum.json delete mode 100644 third-party/vendor/hashlink/CHANGELOG.md delete mode 100644 third-party/vendor/hashlink/Cargo.toml delete mode 100644 third-party/vendor/hashlink/LICENSE-APACHE delete mode 100644 third-party/vendor/hashlink/LICENSE-MIT delete mode 100644 third-party/vendor/hashlink/README.md delete mode 100644 third-party/vendor/hashlink/src/lib.rs delete mode 100644 third-party/vendor/hashlink/src/linked_hash_map.rs delete mode 100644 third-party/vendor/hashlink/src/linked_hash_set.rs delete mode 100644 third-party/vendor/hashlink/src/lru_cache.rs delete mode 100644 third-party/vendor/hashlink/src/serde.rs delete mode 100644 third-party/vendor/hashlink/tests/linked_hash_map.rs delete mode 100644 third-party/vendor/hashlink/tests/linked_hash_set.rs delete mode 100644 third-party/vendor/hashlink/tests/lru_cache.rs delete mode 100644 third-party/vendor/hashlink/tests/serde.rs delete mode 100644 third-party/vendor/heck/.cargo-checksum.json delete mode 100644 third-party/vendor/heck/CHANGELOG.md delete mode 100644 third-party/vendor/heck/Cargo.toml delete mode 100644 third-party/vendor/heck/LICENSE-APACHE delete mode 100644 third-party/vendor/heck/LICENSE-MIT delete mode 100644 third-party/vendor/heck/README.md delete mode 100644 third-party/vendor/heck/src/kebab.rs delete mode 100644 third-party/vendor/heck/src/lib.rs delete mode 100644 third-party/vendor/heck/src/lower_camel.rs delete mode 100644 third-party/vendor/heck/src/shouty_kebab.rs delete mode 100644 third-party/vendor/heck/src/shouty_snake.rs delete mode 100644 third-party/vendor/heck/src/snake.rs delete mode 100644 third-party/vendor/heck/src/title.rs delete mode 100644 third-party/vendor/heck/src/train.rs delete mode 100644 third-party/vendor/heck/src/upper_camel.rs delete mode 100644 third-party/vendor/indenter/.cargo-checksum.json delete mode 100644 third-party/vendor/indenter/CHANGELOG.md delete mode 100644 third-party/vendor/indenter/Cargo.lock delete mode 100644 third-party/vendor/indenter/Cargo.toml delete mode 100644 third-party/vendor/indenter/README.md delete mode 100644 third-party/vendor/indenter/examples/usage.rs delete mode 100644 third-party/vendor/indenter/src/lib.rs delete mode 100644 third-party/vendor/salsa-2022-macros/.cargo-checksum.json delete mode 100644 third-party/vendor/salsa-2022-macros/Cargo.toml delete mode 100644 third-party/vendor/salsa-2022-macros/src/accumulator.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/configuration.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/db.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/input.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/interned.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/jar.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/lib.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/options.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/salsa_struct.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/tracked.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/tracked_fn.rs delete mode 100644 third-party/vendor/salsa-2022-macros/src/tracked_struct.rs delete mode 100644 third-party/vendor/salsa-2022/.cargo-checksum.json delete mode 100644 third-party/vendor/salsa-2022/Cargo.toml delete mode 100644 third-party/vendor/salsa-2022/src/accumulator.rs delete mode 100644 third-party/vendor/salsa-2022/src/cancelled.rs delete mode 100644 third-party/vendor/salsa-2022/src/cycle.rs delete mode 100644 third-party/vendor/salsa-2022/src/database.rs delete mode 100644 third-party/vendor/salsa-2022/src/debug.rs delete mode 100644 third-party/vendor/salsa-2022/src/durability.rs delete mode 100644 third-party/vendor/salsa-2022/src/event.rs delete mode 100644 third-party/vendor/salsa-2022/src/function.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/accumulated.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/backdate.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/delete.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/diff_outputs.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/execute.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/fetch.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/inputs.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/lru.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/maybe_changed_after.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/memo.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/specify.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/store.rs delete mode 100644 third-party/vendor/salsa-2022/src/function/sync.rs delete mode 100644 third-party/vendor/salsa-2022/src/hash.rs delete mode 100644 third-party/vendor/salsa-2022/src/id.rs delete mode 100644 third-party/vendor/salsa-2022/src/ingredient.rs delete mode 100644 third-party/vendor/salsa-2022/src/ingredient_list.rs delete mode 100644 third-party/vendor/salsa-2022/src/input.rs delete mode 100644 third-party/vendor/salsa-2022/src/input_field.rs delete mode 100644 third-party/vendor/salsa-2022/src/interned.rs delete mode 100644 third-party/vendor/salsa-2022/src/jar.rs delete mode 100644 third-party/vendor/salsa-2022/src/key.rs delete mode 100644 third-party/vendor/salsa-2022/src/lib.rs delete mode 100644 third-party/vendor/salsa-2022/src/plumbing.rs delete mode 100644 third-party/vendor/salsa-2022/src/revision.rs delete mode 100644 third-party/vendor/salsa-2022/src/routes.rs delete mode 100644 third-party/vendor/salsa-2022/src/runtime.rs delete mode 100644 third-party/vendor/salsa-2022/src/runtime/active_query.rs delete mode 100644 third-party/vendor/salsa-2022/src/runtime/dependency_graph.rs delete mode 100644 third-party/vendor/salsa-2022/src/runtime/local_state.rs delete mode 100644 third-party/vendor/salsa-2022/src/runtime/shared_state.rs delete mode 100644 third-party/vendor/salsa-2022/src/salsa_struct.rs delete mode 100644 third-party/vendor/salsa-2022/src/setter.rs delete mode 100644 third-party/vendor/salsa-2022/src/storage.rs delete mode 100644 third-party/vendor/salsa-2022/src/tracked_struct.rs diff --git a/Cargo.lock b/Cargo.lock index 61fe7c7d..02570959 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,12 +109,6 @@ version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" -[[package]] -name = "arc-swap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" - [[package]] name = "arrayref" version = "0.3.7" @@ -442,19 +436,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - [[package]] name = "crossbeam-channel" version = "0.5.12" @@ -464,34 +445,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -689,16 +642,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - [[package]] name = "fdeflate" version = "0.3.4" @@ -729,7 +672,6 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "salsa-2022", "syn 2.0.52", "thiserror", "unicode-width", @@ -962,15 +904,6 @@ dependencies = [ "allocator-api2", ] -[[package]] -name = "hashlink" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" -dependencies = [ - "hashbrown 0.14.3", -] - [[package]] name = "hassle-rs" version = "0.10.0" @@ -986,12 +919,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "hermit-abi" version = "0.3.9" @@ -1048,12 +975,6 @@ dependencies = [ "png", ] -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - [[package]] name = "indexmap" version = "1.9.3" @@ -2064,36 +1985,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" -[[package]] -name = "salsa-2022" -version = "0.1.0" -source = "git+https://github.com/salsa-rs/salsa.git#f1d318a2795e87081e316a5f31ef02f0cd6a1c83" -dependencies = [ - "arc-swap", - "crossbeam", - "crossbeam-utils", - "dashmap", - "hashlink", - "indexmap 2.2.5", - "log", - "parking_lot", - "rustc-hash", - "salsa-2022-macros", - "smallvec", -] - -[[package]] -name = "salsa-2022-macros" -version = "0.1.0" -source = "git+https://github.com/salsa-rs/salsa.git#f1d318a2795e87081e316a5f31ef02f0cd6a1c83" -dependencies = [ - "eyre", - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "same-file" version = "1.0.6" diff --git a/fine/Cargo.toml b/fine/Cargo.toml index 52489575..9b0f34c8 100644 --- a/fine/Cargo.toml +++ b/fine/Cargo.toml @@ -16,4 +16,3 @@ syn = "2.0.47" [dependencies] thiserror = "1.0.56" unicode-width = "=0.1.11" -salsa = { git = "https://github.com/salsa-rs/salsa.git", package = "salsa-2022" } \ No newline at end of file diff --git a/third-party/vendor/arc-swap/.cargo-checksum.json b/third-party/vendor/arc-swap/.cargo-checksum.json deleted file mode 100644 index 09952592..00000000 --- a/third-party/vendor/arc-swap/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"c63f740f694a274796862123637146dcc5aceb999eb157e76ec3d6333ed5b7f1","Cargo.toml":"5cb99f81b29e58171a4e3c44440fe25a0a79e09dc8c569ff4a3bd29dab55f322","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff3f1cd12af8866d9bde961d6cc40df774cd131d484de31d3170c4b02b21a7b5","README.md":"51b800d6d0fe42f855dfbd3f8a0e401a8bb276ca52dcec79e2788e64122c484d","TODO":"788f7b1ad8fea31a5ec1b1079f43a23913e615247a92acbd37c0466027c233fe","benches/background.rs":"5f08673a4b5e7935a8ceff2893c88a2de355b5925333b5949ff5f4bc44bcb22e","benches/int-access.rs":"ca730792fd171ac10bcb968af2d87286c1e469b8f2c6abccd2c6d42c72d315eb","benches/track.rs":"785ad6ffc0152b117562312404f75df97ea169e4b07fa8ec9a9595cd30b3fee4","ci-check.sh":"f1ad7ffbb2e996c50633a9168cdd45760af03c4bb9aaf2a4d60b45f41f9413a8","rustfmt.toml":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/access.rs":"284d0d54f45570ccb5d2197c2d5bffe502e88d4c231e601ab70a1f3772ac009c","src/as_raw.rs":"be4cee8ef22ba5125af05d50b93f992531faea17991384f3690d2c481110f087","src/cache.rs":"25b753fbb53c4addaeccae25ee12ad7b77d70ade1af73ca02846797b541872be","src/compile_fail_tests.rs":"4f68cecb0406b0062e01b86879643e26804ae96a04ba0ca6f63caacefae8e567","src/debt/fast.rs":"7ca64acd7f2942707693b6e7476dce7e1bbbcc007129da11142f119fa86e29de","src/debt/helping.rs":"0e0974ba6813a5d28fa974f6bfd9e1c3e35cd480252a7193d091e0a1ff153c03","src/debt/list.rs":"c67fcbfc4fec9158273d0e6b6f1e4168c0e74107516695f43bc374a67968b612","src/debt/mod.rs":"1aa6687a04fd552288d983c1b0ecc8e23cdf14821711f4c82b183f3b64a5628c","src/docs/internal.rs":"4f869ecd5152f45157e5bc6922d0274639cfb389c7172402de9b48d50c26db8b","src/docs/limitations.rs":"b177c990433a8a9b01cd426911c8a57160619a3644b0b82d031484f14d9267a2","src/docs/mod.rs":"c987f5ddf7d6bdc8fa262d6574d353d92a08675e2b521a341636eb0dc129feaa","src/docs/patterns.rs":"07840de45405246fc232fd73061958bd7cb0997150271fd98e153ce9788da390","src/docs/performance.rs":"c9be1f43c67ef26b56f3a32a1231f18a015c83b829276e8c5a8949d0d8ef9f17","src/lib.rs":"3efa46b8bb0153130b4a25ea6779cfeee0de431cb38b6981625ebb993dd2dde1","src/ref_cnt.rs":"8b540a21cbdf7e6f5aff2441b15ca410bf3eba4dfa882aad22accda13bd91995","src/serde.rs":"b1bf117da9e37e85ae6c0bdc281ace575a2030195706d32679d6e54b27522698","src/strategy/hybrid.rs":"9d9a9d1d17d0ad5756de2724699ea7feeea662c9c02738f613d956a5ae0470ed","src/strategy/mod.rs":"0bd567b1be128919c24f057c5f770b6648a9777f44be2e83dd8b29f752144fcc","src/strategy/rw_lock.rs":"2e7717cf52283656754921c5fe0463df9928bac0855d9cf5a9d58362e858a4db","src/strategy/test_strategies.rs":"6520ad9bf6eaddcdcd39ee3392dbadd0f176b875b938b158c9e5ed632d064426","src/weak.rs":"98dc326bfdb3ca88500740f803e43cc7edbc6d858cc2924fb801ce4353124dec","tests/random.rs":"606e71a16fa9cf04f986de76f95e0cce90041ac15894e92d8ebe87e2dc71fc7c","tests/stress.rs":"0ae80d9ec294714d2295333e4c5f7a11a3c2e87bc3f107f1c5f37d7dc3dde354"},"package":"7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f"} \ No newline at end of file diff --git a/third-party/vendor/arc-swap/CHANGELOG.md b/third-party/vendor/arc-swap/CHANGELOG.md deleted file mode 100644 index 718c3cf5..00000000 --- a/third-party/vendor/arc-swap/CHANGELOG.md +++ /dev/null @@ -1,232 +0,0 @@ -# 1.7.1 - -* Support for no-std builds with the `experimental-thread-local`. Needs nightly - compiler. No stability guarantees with this feature (#93). - -# 1.6.0 - -* Fix a data race reported by MIRI. -* Avoid violating stacked borrows (AFAIK these are still experimental and not - normative, but better safe than sorry). (#80). -* The `AccessConvert` wrapper is needed less often in practice (#77). - -# 1.5.1 - -* bug: Insufficient synchronization on weak platforms (#76). - - Never observed in practice (it's suspected practical weak platforms like ARM - are still stronger than the model), but still technically UB. -* docs: Mention triomphe's `ThinArc` around the fat-pointer limitations. - -# 1.5.0 - -* Support serde (by a feature). - -# 1.4.0 - -* Allow const-initializing ArcSwapOption (`const_empty` method). - -# 1.3.2 - -* More helpful description of the `AsRaw` trait (isn't implemented for owned - `Arc`/`Option`). - -# 1.3.1 - -* Cache doc improvements. - -# 1.3.0 - -* Allow mapping of DynAccess. -* Fix some lints. -* Don't leave threads running in tests/doctests. It's a bad form and annoys - miri. - -# 1.2.0 - -* Miri and 32 bit tests in CI. -* Making the writers lock-free. Soft-removing the IndependentStrategy, as it is - no longer needed (hidden and the same as the DafultStrategy). - -# 1.1.0 - -* Fix soundness bug around access::Map. Technically a breaking change, but - unlikely to bite and breaking seems to be the least bad option. #45. - -# 1.0.0 - -* Remove Clone implementation. People are often confused by it and it is easy to - emulate by hand in the rare case it is actually needed. - -# 1.0.0-rc1 - -* Get rid of the `load_signal_safe`. It only complicates things and it is niche; - signal-hook-registry has its own simplified version. -* Avoid `from_ptr(as_ptr())`. Slight change in `RefCnt::inc` which technically - is API breaking change, but this one should not matter in practice. -* Extend documentation about clone behaviour. -* Few more traits for Guard (`From`, `Default`). -* Get rid of `rcu_unwap`, the whole concept is a trap. -* Hide the whole gen lock thing. -* Introduce the `Strategy`, as a high level way to choose how exactly the - locking happens. - - Not possible to implement by downstream users just yet, or call them. - - The CaS is its own trait for flexibility. -* Adding the SimpleGenLock experimental strategy. - - Not part of stability guarantees. - -# 0.4.7 - -* Rename the `unstable-weak` to `weak` feature. The support is now available on - 1.45 (currently in beta). - -# 0.4.6 - -* Adjust to `Weak::as_ptr` from std (the weak pointer support, relying on - unstable features). -* Support running on miri (without some optimizations), so dependencies may run - miri tests. -* Little optimization when waiting out the contention on write operations. - -# 0.4.5 - -* Added `Guard::from_inner`. - -# 0.4.4 - -* Top-level docs rewrite (less rambling, hopefully more readable). - -# 0.4.3 - -* Fix the `Display` implementation on `Guard` to correctly delegate to the - underlying `Display` implementation. - -# 0.4.2 - -* The Access functionality ‒ ability to pass a handle to subpart of held data to - somewhere with the ability to update itself. -* Mapped cache can take `FnMut` as well as `Fn`. - -# 0.4.1 - -* Mapped caches ‒ to allow giving access to parts of config only. - -# 0.4.0 - -* Support for Weak pointers. -* RefCnt implemented for Rc. -* Breaking: Big API cleanups. - - Peek is gone. - - Terminology of getting the data unified to `load`. - - There's only one kind of `Guard` now. - - Guard derefs to the `Arc`/`Option` or similar. - - `Cache` got moved to top level of the crate. - - Several now unneeded semi-internal traits and trait methods got removed. -* Splitting benchmarks into a separate sub-crate. -* Minor documentation improvements. - -# 0.3.11 - -* Prevention against UB due to dropping Guards and overflowing the guard - counter (aborting instead, such problem is very degenerate anyway and wouldn't - work in the first place). - -# 0.3.10 - -* Tweak slot allocation to take smaller performance hit if some leases are held. -* Increase the number of lease slots per thread to 8. -* Added a cache for faster access by keeping an already loaded instance around. - -# 0.3.9 - -* Fix Send/Sync for Guard and Lease (they were broken in the safe but - uncomfortable direction ‒ not implementing them even if they could). - -# 0.3.8 - -* `Lease>::unwrap()`, `expect()` and `into_option()` for convenient - use. - -# 0.3.7 - -* Use the correct `#[deprecated]` syntax. - -# 0.3.6 - -* Another locking store (`PrivateSharded`) to complement the global and private - unsharded ones. -* Comparison to other crates/approaches in the docs. - -# 0.3.5 - -* Updates to documentation, made it hopefully easier to digest. -* Added the ability to separate gen-locks of one ArcSwapAny from others. -* Some speed improvements by inlining. -* Simplified the `lease` method internally, making it faster in optimistic - cases. - -# 0.3.4 - -* Another potentially weak ordering discovered (with even less practical effect - than the previous). - -# 0.3.3 - -* Increased potentially weak ordering (probably without any practical effect). - -# 0.3.2 - -* Documentation link fix. - -# 0.3.1 - -* Few convenience constructors. -* More tests (some randomized property testing). - -# 0.3.0 - -* `compare_and_swap` no longer takes `&Guard` as current as that is a sure way - to create a deadlock. -* Introduced `Lease` for temporary storage, which doesn't suffer from contention - like `load`, but doesn't block writes like `Guard`. The downside is it slows - down with number of held by the current thread. -* `compare_and_swap` and `rcu` uses leases. -* Made the `ArcSwap` as small as the pointer itself, by making the - shards/counters and generation ID global. This comes at a theoretical cost of - more contention when different threads use different instances. - -# 0.2.0 - -* Added an `ArcSwapOption`, which allows storing NULL values (as None) as well - as a valid pointer. -* `compare_and_swap` accepts borrowed `Arc` as `current` and doesn't consume one - ref count. -* Sharding internal counters, to improve performance on read-mostly contented - scenarios. -* Providing `peek_signal_safe` as the only async signal safe method to use - inside signal handlers. This removes the footgun with dropping the `Arc` - returned from `load` inside a signal handler. - -# 0.1.4 - -* The `peek` method to use the `Arc` inside without incrementing the reference - count. -* Some more (and hopefully better) benchmarks. - -# 0.1.3 - -* Documentation fix (swap is *not* lock-free in current implementation). - -# 0.1.2 - -* More freedom in the `rcu` and `rcu_unwrap` return types. - -# 0.1.1 - -* `rcu` support. -* `compare_and_swap` support. -* Added some primitive benchmarks. - -# 0.1.0 - -* Initial implementation. diff --git a/third-party/vendor/arc-swap/Cargo.toml b/third-party/vendor/arc-swap/Cargo.toml deleted file mode 100644 index 06484c55..00000000 --- a/third-party/vendor/arc-swap/Cargo.toml +++ /dev/null @@ -1,91 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -name = "arc-swap" -version = "1.7.0" -authors = ["Michal 'vorner' Vaner "] -description = "Atomically swappable Arc" -documentation = "https://docs.rs/arc-swap" -readme = "README.md" -keywords = [ - "atomic", - "Arc", -] -categories = [ - "data-structures", - "memory-management", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/vorner/arc-swap" - -[package.metadata.docs.rs] -all-features = true - -[profile.bench] -debug = 2 - -[[bench]] -name = "background" -harness = false - -[[bench]] -name = "int-access" -harness = false - -[[bench]] -name = "track" -harness = false - -[dependencies.serde] -version = "1" -features = ["rc"] -optional = true - -[dev-dependencies.adaptive-barrier] -version = "~1" - -[dev-dependencies.criterion] -version = "~0.5" - -[dev-dependencies.crossbeam-utils] -version = "~0.8" - -[dev-dependencies.itertools] -version = "0.12" - -[dev-dependencies.num_cpus] -version = "~1" - -[dev-dependencies.once_cell] -version = "~1" - -[dev-dependencies.parking_lot] -version = "~0.12" - -[dev-dependencies.proptest] -version = "1" - -[dev-dependencies.serde_derive] -version = "1.0.130" - -[dev-dependencies.serde_test] -version = "1.0.130" - -[features] -experimental-strategies = [] -experimental-thread-local = [] -internal-test-strategies = [] -weak = [] - -[badges.maintenance] -status = "actively-developed" diff --git a/third-party/vendor/arc-swap/LICENSE-APACHE b/third-party/vendor/arc-swap/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/third-party/vendor/arc-swap/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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/third-party/vendor/arc-swap/LICENSE-MIT b/third-party/vendor/arc-swap/LICENSE-MIT deleted file mode 100644 index b4e28573..00000000 --- a/third-party/vendor/arc-swap/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2017 arc-swap developers - -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/third-party/vendor/arc-swap/README.md b/third-party/vendor/arc-swap/README.md deleted file mode 100644 index 5667add6..00000000 --- a/third-party/vendor/arc-swap/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# ArcSwap - -[![Actions Status](https://github.com/vorner/arc-swap/workflows/test/badge.svg)](https://github.com/vorner/arc-swap/actions) -[![codecov](https://codecov.io/gh/vorner/arc-swap/branch/master/graph/badge.svg?token=3KA3R2D9fV)](https://codecov.io/gh/vorner/arc-swap) -[![docs](https://docs.rs/arc-swap/badge.svg)](https://docs.rs/arc-swap) - -This provides something similar to what `RwLock>` is or what -`Atomic>` would be if it existed, optimized for read-mostly write-seldom -scenarios, with consistent performance characteristics. - -Read [the documentation](https://docs.rs/arc-swap) before using. - -## Rust version policy - -The 1. version will build on any edition 2018 capable compiler. This does not -include: - -* Tests. Tests build and run on recent compilers, mostly because of - dependencies. -* Additional feature flags. Most feature flags are guaranteed to build since the - version they are introduced. Experimental features are without any guarantees. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms -or conditions. - -[`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html -[`AtomicPtr`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html -[`ArcSwap`]: https://docs.rs/arc-swap/*/arc_swap/type.ArcSwap.html diff --git a/third-party/vendor/arc-swap/TODO b/third-party/vendor/arc-swap/TODO deleted file mode 100644 index 3bb6c07d..00000000 --- a/third-party/vendor/arc-swap/TODO +++ /dev/null @@ -1 +0,0 @@ -* A cache without the thing inside ‒ passed to load every time. Possibly with multiple cached values. diff --git a/third-party/vendor/arc-swap/benches/background.rs b/third-party/vendor/arc-swap/benches/background.rs deleted file mode 100644 index be1c2e17..00000000 --- a/third-party/vendor/arc-swap/benches/background.rs +++ /dev/null @@ -1,335 +0,0 @@ -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; - -use arc_swap::{ArcSwap, ArcSwapOption, Cache}; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use crossbeam_utils::thread; -use once_cell::sync::Lazy; - -// Mostly a leftover from earlier times, but it still allows one to tweak the number of ops per one -// iteration of the benchmark easily, so it's left in here. -const ITERS: usize = 1; - -macro_rules! method { - ($c: expr, $name:ident) => {{ - let mut g = $c.benchmark_group(&format!("{}_{}", NAME, stringify!($name))); - noise(&mut g, "r1", 1, 0, 0, $name); - noise(&mut g, "r3", 3, 0, 0, $name); - noise(&mut g, "l1", 0, 1, 0, $name); - noise(&mut g, "l3", 0, 3, 0, $name); - noise(&mut g, "rw", 1, 0, 1, $name); - noise(&mut g, "lw", 0, 1, 1, $name); - noise(&mut g, "w2", 0, 0, 2, $name); - g.bench_function("uncontended", |b| b.iter($name)); - g.finish(); - }}; -} - -macro_rules! noise { - () => { - use criterion::measurement::Measurement; - use criterion::BenchmarkGroup; - - use super::{thread, Arc, AtomicBool, Ordering, ITERS}; - - fn noise( - g: &mut BenchmarkGroup, - name: &str, - readers: usize, - leasers: usize, - writers: usize, - f: F, - ) { - let flag = Arc::new(AtomicBool::new(true)); - thread::scope(|s| { - for _ in 0..readers { - s.spawn(|_| { - while flag.load(Ordering::Relaxed) { - read(); - } - }); - } - for _ in 0..leasers { - s.spawn(|_| { - while flag.load(Ordering::Relaxed) { - lease(); - } - }); - } - for _ in 0..writers { - s.spawn(|_| { - while flag.load(Ordering::Relaxed) { - write(); - } - }); - } - g.bench_function(name, |b| b.iter(&f)); - flag.store(false, Ordering::Relaxed); - }) - .unwrap(); - } - }; -} - -macro_rules! strategy { - ($name: ident, $type: ty) => { - mod $name { - use super::*; - - static A: Lazy<$type> = Lazy::new(|| <$type>::from_pointee(0)); - const NAME: &str = stringify!($name); - - fn lease() { - for _ in 0..ITERS { - black_box(**A.load()); - } - } - - // Leases kind of degrade in performance if there are multiple on the same thread. - fn four_leases() { - for _ in 0..ITERS { - let l1 = A.load(); - let l2 = A.load(); - let l3 = A.load(); - let l4 = A.load(); - black_box((**l1, **l2, **l3, **l4)); - } - } - - fn read() { - for _ in 0..ITERS { - black_box(A.load_full()); - } - } - - fn write() { - for _ in 0..ITERS { - black_box(A.store(Arc::new(0))); - } - } - - noise!(); - - pub fn run_all(c: &mut Criterion) { - method!(c, read); - method!(c, write); - method!(c, lease); - method!(c, four_leases); - } - } - }; -} - -strategy!(arc_swap_b, ArcSwap::); - -mod arc_swap_option { - use super::{black_box, ArcSwapOption, Criterion, Lazy}; - - static A: Lazy> = Lazy::new(|| ArcSwapOption::from(None)); - const NAME: &str = "arc_swap_option"; - - fn lease() { - for _ in 0..ITERS { - black_box(A.load().as_ref().map(|l| **l).unwrap_or(0)); - } - } - - fn read() { - for _ in 0..ITERS { - black_box(A.load_full().map(|a| -> usize { *a }).unwrap_or(0)); - } - } - - fn write() { - for _ in 0..ITERS { - black_box(A.store(Some(Arc::new(0)))); - } - } - - noise!(); - - pub fn run_all(c: &mut Criterion) { - method!(c, read); - method!(c, write); - method!(c, lease); - } -} - -mod arc_swap_cached { - use super::{black_box, ArcSwap, Cache, Criterion, Lazy}; - - static A: Lazy> = Lazy::new(|| ArcSwap::from_pointee(0)); - const NAME: &str = "arc_swap_cached"; - - fn read() { - let mut cache = Cache::from(&A as &ArcSwap); - for _ in 0..ITERS { - black_box(Arc::clone(cache.load())); - } - } - - fn lease() { - for _ in 0..ITERS { - black_box(**A.load()); - } - } - - fn write() { - for _ in 0..ITERS { - black_box(A.store(Arc::new(0))); - } - } - - noise!(); - - pub fn run_all(c: &mut Criterion) { - method!(c, read); - method!(c, write); - } -} - -mod mutex { - use super::{black_box, Criterion, Lazy, Mutex}; - - static M: Lazy>> = Lazy::new(|| Mutex::new(Arc::new(0))); - const NAME: &str = "mutex"; - - fn lease() { - for _ in 0..ITERS { - black_box(**M.lock().unwrap()); - } - } - - fn read() { - for _ in 0..ITERS { - black_box(Arc::clone(&*M.lock().unwrap())); - } - } - - fn write() { - for _ in 0..ITERS { - black_box(*M.lock().unwrap() = Arc::new(42)); - } - } - - noise!(); - - pub fn run_all(c: &mut Criterion) { - method!(c, read); - method!(c, write); - } -} - -mod parking_mutex { - use parking_lot::Mutex as ParkingMutex; - - use super::{black_box, Criterion, Lazy}; - - static M: Lazy>> = Lazy::new(|| ParkingMutex::new(Arc::new(0))); - const NAME: &str = "parking_mutex"; - - fn lease() { - for _ in 0..ITERS { - black_box(**M.lock()); - } - } - - fn read() { - for _ in 0..ITERS { - black_box(Arc::clone(&*M.lock())); - } - } - - fn write() { - for _ in 0..ITERS { - black_box(*M.lock() = Arc::new(42)); - } - } - - noise!(); - - pub fn run_all(c: &mut Criterion) { - method!(c, read); - method!(c, write); - } -} - -mod rwlock { - use std::sync::RwLock; - - use super::{black_box, Criterion, Lazy}; - - static L: Lazy>> = Lazy::new(|| RwLock::new(Arc::new(0))); - const NAME: &str = "rwlock"; - - fn lease() { - for _ in 0..ITERS { - black_box(**L.read().unwrap()); - } - } - - fn read() { - for _ in 0..ITERS { - black_box(Arc::clone(&*L.read().unwrap())); - } - } - - fn write() { - for _ in 0..ITERS { - black_box(*L.write().unwrap() = Arc::new(42)); - } - } - - noise!(); - - pub fn run_all(c: &mut Criterion) { - method!(c, read); - method!(c, write); - } -} - -mod parking_rwlock { - use parking_lot::RwLock; - - use super::{black_box, Criterion, Lazy}; - - static L: Lazy>> = Lazy::new(|| RwLock::new(Arc::new(0))); - const NAME: &str = "parking_rwlock"; - - fn lease() { - for _ in 0..ITERS { - black_box(**L.read()); - } - } - - fn read() { - for _ in 0..ITERS { - black_box(Arc::clone(&*L.read())); - } - } - - fn write() { - for _ in 0..ITERS { - black_box(*L.write() = Arc::new(42)); - } - } - - noise!(); - - pub fn run_all(c: &mut Criterion) { - method!(c, read); - method!(c, write); - } -} - -criterion_group!( - benches, - arc_swap_b::run_all, - arc_swap_option::run_all, - arc_swap_cached::run_all, - mutex::run_all, - parking_mutex::run_all, - rwlock::run_all, - parking_rwlock::run_all, -); -criterion_main!(benches); diff --git a/third-party/vendor/arc-swap/benches/int-access.rs b/third-party/vendor/arc-swap/benches/int-access.rs deleted file mode 100644 index 78ae83a8..00000000 --- a/third-party/vendor/arc-swap/benches/int-access.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! These are very minimal benchmarks ‒ reading and writing an integer shared in -//! different ways. You can compare the times and see the characteristics. - -use std::io::{self, Write}; -use std::sync::{Arc, Mutex, RwLock}; -use std::time::Instant; - -use arc_swap::ArcSwap; -use criterion::black_box; -use crossbeam_utils::thread; - -fn test_run( - name: &str, - read_threads: usize, - write_threads: usize, - iterations: usize, - r: R, - w: W, -) where - R: Fn() -> usize + Sync + Send, - W: Fn(usize) + Sync + Send, -{ - print!( - "{:20} ({} + {}) x {}: ", - name, read_threads, write_threads, iterations - ); - io::stdout().flush().unwrap(); - let before = Instant::now(); - thread::scope(|scope| { - for _ in 0..read_threads { - scope.spawn(|_| { - for _ in 0..iterations { - black_box(r()); - } - }); - } - for _ in 0..write_threads { - scope.spawn(|_| { - for i in 0..iterations { - black_box(w(i)); - } - }); - } - }) - .unwrap(); - let duration = Instant::now() - before; - println!( - "{:03}.{:03}s", - duration.as_secs(), - duration.subsec_nanos() / 100_000 - ); -} - -fn test_round(name: &str, iterations: usize, r: R, w: W) -where - R: Fn() -> usize + Sync + Send, - W: Fn(usize) + Sync + Send, -{ - test_run(name, 1, 0, iterations, &r, &w); - test_run(name, 2, 0, iterations, &r, &w); - test_run(name, 4, 0, iterations, &r, &w); - test_run(name, 8, 0, iterations, &r, &w); - test_run(name, 1, 1, iterations, &r, &w); - test_run(name, 4, 1, iterations, &r, &w); - test_run(name, 4, 2, iterations, &r, &w); - test_run(name, 4, 4, iterations, &r, &w); - test_run(name, 8, 1, iterations, &r, &w); - test_run(name, 8, 2, iterations, &r, &w); - test_run(name, 8, 4, iterations, &r, &w); - test_run(name, 0, 1, iterations, &r, &w); - test_run(name, 0, 4, iterations, &r, &w); -} - -fn main() { - let mutex = Mutex::new(42); - test_round( - "mutex", - 100_000, - || *mutex.lock().unwrap(), - |i| *mutex.lock().unwrap() = i, - ); - let mutex = Mutex::new(Arc::new(42)); - test_round( - "mutex-arc", - 100_000, - || **mutex.lock().unwrap(), - |i| *mutex.lock().unwrap() = Arc::new(i), - ); - test_round( - "mutex-arc-clone", - 100_000, - || *Arc::clone(&*mutex.lock().unwrap()), - |i| *mutex.lock().unwrap() = Arc::new(i), - ); - let lock = RwLock::new(42); - test_round( - "rw", - 100_000, - || *lock.read().unwrap(), - |i| *lock.write().unwrap() = i, - ); - let lock = RwLock::new(Arc::new(42)); - test_round( - "rw-arc", - 100_000, - || **lock.read().unwrap(), - |i| *lock.write().unwrap() = Arc::new(i), - ); - test_round( - "rw-arc-clone", - 100_000, - || *Arc::clone(&*lock.read().unwrap()), - |i| *lock.write().unwrap() = Arc::new(i), - ); - let arc = ArcSwap::from(Arc::new(42)); - test_round( - "arc-load-store", - 100_000, - || **arc.load(), - |i| arc.store(Arc::new(i)), - ); - test_round( - "arc-rcu", - 100_000, - || *arc.load_full(), - |i| { - arc.rcu(|_| Arc::new(i)); - }, - ); -} diff --git a/third-party/vendor/arc-swap/benches/track.rs b/third-party/vendor/arc-swap/benches/track.rs deleted file mode 100644 index 987439a6..00000000 --- a/third-party/vendor/arc-swap/benches/track.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Benchmarks to track basic performance across changes. -//! -//! Slightly based on the benchmarks, but simplified and stripped down to run -//! reasonably fast. - -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - -use arc_swap::access::{Access, Map}; -use arc_swap::cache::Cache; -use arc_swap::ArcSwap; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use crossbeam_utils::thread; - -/// Execute a group of measurements -/// -/// It expects any kind of „environment“ is already in place for it. -fn batch(c: &mut Criterion, name: &str, shared_number: &ArcSwap) { - let mut g = c.benchmark_group(name); - - g.bench_function("load", |b| { - b.iter(|| { - black_box(shared_number.load()); - }) - }); - g.bench_function("load_full", |b| { - b.iter(|| { - black_box(shared_number.load_full()); - }) - }); - g.bench_function("load_many", |b| { - // Here we simulate running out of the debt slots scenario - const MANY: usize = 32; - let mut guards = Vec::with_capacity(MANY); - b.iter(|| { - guards.push(black_box(shared_number.load())); - if guards.len() == MANY { - guards.clear(); - } - }) - }); - g.bench_function("store", |b| { - b.iter(|| { - black_box(shared_number.store(Arc::new(42))); - }) - }); - g.bench_function("cache", |b| { - let mut cache = Cache::new(shared_number); - b.iter(|| { - black_box(cache.load()); - }) - }); - - g.finish(); -} - -fn with_background) + Sync>( - c: &mut Criterion, - name: &str, - cnt: usize, - noise: F, -) { - let stop = AtomicBool::new(false); - let shared_number = ArcSwap::from_pointee(42); - thread::scope(|s| { - // Start some background noise threads, to contend the arc swap. - for _ in 0..cnt { - s.spawn(|_| { - while !stop.load(Ordering::Relaxed) { - noise(&shared_number); - } - }); - } - - // Perform the benchmarks - batch(c, name, &shared_number); - - // Ask the threads to terminate, so they don't disturb any other banchmarks - stop.store(true, Ordering::Relaxed); - }) - .unwrap(); -} - -fn utilities(c: &mut Criterion) { - let mut g = c.benchmark_group("utilities"); - - struct Composed { - val: i32, - } - - g.bench_function("access-map", |b| { - let a = Arc::new(ArcSwap::from_pointee(Composed { val: 42 })); - let m = Map::new(Arc::clone(&a), |c: &Composed| &c.val); - b.iter(|| { - let g = black_box(m.load()); - assert_eq!(42, *g); - }); - }); -} - -fn benchmark(c: &mut Criterion) { - batch(c, "uncontended", &ArcSwap::from_pointee(42)); - with_background(c, "concurrent_loads", 2, |s| { - black_box(s.load()); - }); - with_background(c, "concurrent_store", 1, |s| { - black_box(s.store(Arc::new(42))); - }); - utilities(c); -} - -criterion_group!(benches, benchmark); -criterion_main!(benches); diff --git a/third-party/vendor/arc-swap/ci-check.sh b/third-party/vendor/arc-swap/ci-check.sh deleted file mode 100755 index 0a90991f..00000000 --- a/third-party/vendor/arc-swap/ci-check.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -set -ex - -rm -f Cargo.lock -cargo build - -if [ "$RUST_VERSION" = 1.31.0 ] ; then - exit -fi - -# Allow some warnings on the very old compiler. -export RUSTFLAGS="-D warnings" - -cargo test --release --features weak,internal-test-strategies,experimental-strategies -cargo test --release --features weak,internal-test-strategies,experimental-strategies -- --ignored diff --git a/third-party/vendor/arc-swap/rustfmt.toml b/third-party/vendor/arc-swap/rustfmt.toml deleted file mode 100644 index e69de29b..00000000 diff --git a/third-party/vendor/arc-swap/src/access.rs b/third-party/vendor/arc-swap/src/access.rs deleted file mode 100644 index 35d34db0..00000000 --- a/third-party/vendor/arc-swap/src/access.rs +++ /dev/null @@ -1,546 +0,0 @@ -#![deny(unsafe_code)] - -//! Abstracting over accessing parts of stored value. -//! -//! Sometimes, there's a big globalish data structure (like a configuration for the whole program). -//! Then there are parts of the program that need access to up-to-date version of their *part* of -//! the configuration, but for reasons of code separation and reusability, it is not desirable to -//! pass the whole configuration to each of the parts. -//! -//! This module provides means to grant the parts access to the relevant subsets of such global -//! data structure while masking the fact it is part of the bigger whole from the component. -//! -//! Note that the [`cache`][crate::cache] module has its own [`Access`][crate::cache::Access] trait -//! that serves a similar purpose, but with cached access. The signatures are different, therefore -//! an incompatible trait. -//! -//! # The general idea -//! -//! Each part of the code accepts generic [`Access`][Access] for the `T` of its interest. This -//! provides means to load current version of the structure behind the scenes and get only the -//! relevant part, without knowing what the big structure is. -//! -//! For technical reasons, the [`Access`] trait is not object safe. If type erasure is desired, it -//! is possible use the [`DynAccess`][crate::access::DynAccess] instead, which is object safe, but -//! slightly slower. -//! -//! For some cases, it is possible to use [`ArcSwapAny::map`]. If that is not flexible enough, the -//! [`Map`] type can be created directly. -//! -//! Note that the [`Access`] trait is also implemented for [`ArcSwapAny`] itself. Additionally, -//! there's the [`Constant`][crate::access::Constant] helper type, which is useful mostly for -//! testing (it doesn't allow reloading). -//! -//! # Performance -//! -//! In general, these utilities use [`ArcSwapAny::load`] internally and then apply the provided -//! transformation. This has several consequences: -//! -//! * Limitations of the [`load`][ArcSwapAny::load] apply ‒ including the recommendation to not -//! hold the returned guard object for too long, but long enough to get consistency. -//! * The transformation should be cheap ‒ optimally just borrowing into the structure. -//! -//! # Examples -//! -//! ```rust -//! use std::sync::Arc; -//! use std::thread::{self, JoinHandle}; -//! use std::time::Duration; -//! -//! use arc_swap::ArcSwap; -//! use arc_swap::access::{Access, Constant, Map}; -//! -//! fn work_with_usize + Send + 'static>(a: A) -> JoinHandle<()> { -//! thread::spawn(move || { -//! let mut value = 0; -//! while value != 42 { -//! let guard = a.load(); -//! value = *guard; -//! println!("{}", value); -//! // Not strictly necessary, but dropping the guard can free some resources, like -//! // slots for tracking what values are still in use. We do it before the sleeping, -//! // not at the end of the scope. -//! drop(guard); -//! thread::sleep(Duration::from_millis(50)); -//! } -//! }) -//! } -//! -//! // Passing the whole thing directly -//! // (If we kept another Arc to it, we could change the value behind the scenes) -//! work_with_usize(Arc::new(ArcSwap::from_pointee(42))).join().unwrap(); -//! -//! // Passing a subset of a structure -//! struct Cfg { -//! value: usize, -//! } -//! -//! let cfg = Arc::new(ArcSwap::from_pointee(Cfg { value: 0 })); -//! let thread = work_with_usize(Map::new(Arc::clone(&cfg), |cfg: &Cfg| &cfg.value)); -//! cfg.store(Arc::new(Cfg { value: 42 })); -//! thread.join().unwrap(); -//! -//! // Passing a constant that can't change. Useful mostly for testing purposes. -//! work_with_usize(Constant(42)).join().unwrap(); -//! ``` -use core::marker::PhantomData; -use core::ops::Deref; - -use alloc::boxed::Box; -use alloc::rc::Rc; -use alloc::sync::Arc; - -use super::ref_cnt::RefCnt; -use super::strategy::Strategy; -use super::{ArcSwapAny, Guard}; - -/// Abstracts over ways code can get access to a value of type `T`. -/// -/// This is the trait that parts of code will use when accessing a subpart of the big data -/// structure. See the [module documentation](index.html) for details. -pub trait Access { - /// A guard object containing the value and keeping it alive. - /// - /// For technical reasons, the library doesn't allow direct access into the stored value. A - /// temporary guard object must be loaded, that keeps the actual value alive for the time of - /// use. - type Guard: Deref; - - /// The loading method. - /// - /// This returns the guard that holds the actual value. Should be called anew each time a fresh - /// value is needed. - fn load(&self) -> Self::Guard; -} - -impl + ?Sized, P: Deref> Access for P { - type Guard = A::Guard; - fn load(&self) -> Self::Guard { - self.deref().load() - } -} - -impl Access for dyn DynAccess + '_ { - type Guard = DynGuard; - - fn load(&self) -> Self::Guard { - self.load() - } -} - -impl Access for dyn DynAccess + '_ + Send { - type Guard = DynGuard; - - fn load(&self) -> Self::Guard { - self.load() - } -} - -impl Access for dyn DynAccess + '_ + Sync + Send { - type Guard = DynGuard; - - fn load(&self) -> Self::Guard { - self.load() - } -} - -impl> Access for ArcSwapAny { - type Guard = Guard; - - fn load(&self) -> Self::Guard { - self.load() - } -} - -#[derive(Debug)] -#[doc(hidden)] -pub struct DirectDeref>(Guard); - -impl>> Deref for DirectDeref, S> { - type Target = T; - fn deref(&self) -> &T { - self.0.deref().deref() - } -} - -impl>> Access for ArcSwapAny, S> { - type Guard = DirectDeref, S>; - fn load(&self) -> Self::Guard { - DirectDeref(self.load()) - } -} - -impl>> Deref for DirectDeref, S> { - type Target = T; - fn deref(&self) -> &T { - self.0.deref().deref() - } -} - -impl>> Access for ArcSwapAny, S> { - type Guard = DirectDeref, S>; - fn load(&self) -> Self::Guard { - DirectDeref(self.load()) - } -} - -#[doc(hidden)] -pub struct DynGuard(Box>); - -impl Deref for DynGuard { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } -} - -/// An object-safe version of the [`Access`] trait. -/// -/// This can be used instead of the [`Access`] trait in case a type erasure is desired. This has -/// the effect of performance hit (due to boxing of the result and due to dynamic dispatch), but -/// makes certain code simpler and possibly makes the executable smaller. -/// -/// This is automatically implemented for everything that implements [`Access`]. -/// -/// # Examples -/// -/// ```rust -/// use arc_swap::access::{Constant, DynAccess}; -/// -/// fn do_something(value: Box + Send>) { -/// let v = value.load(); -/// println!("{}", *v); -/// } -/// -/// do_something(Box::new(Constant(42))); -/// ``` -pub trait DynAccess { - /// The equivalent of [`Access::load`]. - fn load(&self) -> DynGuard; -} - -impl DynAccess for A -where - A: Access, - A::Guard: 'static, -{ - fn load(&self) -> DynGuard { - DynGuard(Box::new(Access::load(self))) - } -} - -/// [DynAccess] to [Access] wrapper. -/// -/// In previous versions, `Box` didn't implement [Access], to use inside [Map] one -/// could use this wrapper. Since then, a way was found to solve it. In most cases, this wrapper is -/// no longer necessary. -/// -/// This is left in place for two reasons: -/// * Backwards compatibility. -/// * Corner-cases not covered by the found solution. For example, trait inheritance in the form of -/// `Box` where `SomeTrait: Access` doesn't work out of the box and still needs -/// this wrapper. -/// -/// # Examples -/// -/// The example is for the simple case (which is no longer needed, but may help as an inspiration). -/// -/// ```rust -/// use std::sync::Arc; -/// -/// use arc_swap::ArcSwap; -/// use arc_swap::access::{AccessConvert, DynAccess, Map}; -/// -/// struct Inner { -/// val: usize, -/// } -/// -/// struct Middle { -/// inner: Inner, -/// } -/// -/// struct Outer { -/// middle: Middle, -/// } -/// -/// let outer = Arc::new(ArcSwap::from_pointee(Outer { -/// middle: Middle { -/// inner: Inner { -/// val: 42, -/// } -/// } -/// })); -/// -/// let middle: Arc> = -/// Arc::new(Map::new(outer, |outer: &Outer| &outer.middle)); -/// let inner: Arc> = -/// Arc::new(Map::new(AccessConvert(middle), |middle: &Middle| &middle.inner)); -/// let guard = inner.load(); -/// assert_eq!(42, guard.val); -/// ``` -pub struct AccessConvert(pub D); - -impl Access for AccessConvert -where - D: Deref, - D::Target: DynAccess, -{ - type Guard = DynGuard; - - fn load(&self) -> Self::Guard { - self.0.load() - } -} - -#[doc(hidden)] -#[derive(Copy, Clone, Debug)] -pub struct MapGuard { - guard: G, - projection: F, - _t: PhantomData &R>, -} - -impl Deref for MapGuard -where - G: Deref, - F: Fn(&T) -> &R, -{ - type Target = R; - fn deref(&self) -> &R { - (self.projection)(&self.guard) - } -} - -/// An adaptor to provide access to a part of larger structure. -/// -/// This is the *active* part of this module. Use the [module documentation](index.html) for the -/// details. -#[derive(Copy, Clone, Debug)] -pub struct Map { - access: A, - projection: F, - _t: PhantomData T>, -} - -impl Map { - /// Creates a new instance. - /// - /// # Parameters - /// - /// * `access`: Access to the bigger structure. This is usually something like `Arc` - /// or `&ArcSwap`. It is technically possible to use any other [`Access`] here, though, for - /// example to sub-delegate into even smaller structure from a [`Map`] (or generic - /// [`Access`]). - /// * `projection`: A function (or closure) responsible to providing a reference into the - /// bigger bigger structure, selecting just subset of it. In general, it is expected to be - /// *cheap* (like only taking reference). - pub fn new(access: A, projection: F) -> Self - where - F: Fn(&T) -> &R + Clone, - { - Map { - access, - projection, - _t: PhantomData, - } - } -} - -impl Access for Map -where - A: Access, - F: Fn(&T) -> &R + Clone, -{ - type Guard = MapGuard; - fn load(&self) -> Self::Guard { - let guard = self.access.load(); - MapGuard { - guard, - projection: self.projection.clone(), - _t: PhantomData, - } - } -} - -#[doc(hidden)] -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct ConstantDeref(T); - -impl Deref for ConstantDeref { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } -} - -/// Access to an constant. -/// -/// This wraps a constant value to provide [`Access`] to it. It is constant in the sense that, -/// unlike [`ArcSwapAny`] and [`Map`], the loaded value will always stay the same (there's no -/// remote `store`). -/// -/// The purpose is mostly testing and plugging a parameter that works generically from code that -/// doesn't need the updating functionality. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct Constant(pub T); - -impl Access for Constant { - type Guard = ConstantDeref; - fn load(&self) -> Self::Guard { - ConstantDeref(self.0.clone()) - } -} - -#[cfg(test)] -mod tests { - use super::super::{ArcSwap, ArcSwapOption}; - - use super::*; - - fn check_static_dispatch_direct>(a: A) { - assert_eq!(42, *a.load()); - } - - fn check_static_dispatch>>(a: A) { - assert_eq!(42, **a.load()); - } - - /// Tests dispatching statically from arc-swap works - #[test] - fn static_dispatch() { - let a = ArcSwap::from_pointee(42); - check_static_dispatch_direct(&a); - check_static_dispatch(&a); - check_static_dispatch(a); - } - - fn check_dyn_dispatch_direct(a: &dyn DynAccess) { - assert_eq!(42, *a.load()); - } - - fn check_dyn_dispatch(a: &dyn DynAccess>) { - assert_eq!(42, **a.load()); - } - - /// Tests we can also do a dynamic dispatch of the companion trait - #[test] - fn dyn_dispatch() { - let a = ArcSwap::from_pointee(42); - check_dyn_dispatch_direct(&a); - check_dyn_dispatch(&a); - } - - fn check_transition(a: A) - where - A: Access, - A::Guard: 'static, - { - check_dyn_dispatch_direct(&a) - } - - /// Tests we can easily transition from the static dispatch trait to the dynamic one - #[test] - fn transition() { - let a = ArcSwap::from_pointee(42); - check_transition(&a); - check_transition(a); - } - - /// Test we can dispatch from Arc> or similar. - #[test] - fn indirect() { - let a = Arc::new(ArcSwap::from_pointee(42)); - check_static_dispatch(&a); - check_dyn_dispatch(&a); - } - - struct Cfg { - value: usize, - } - - #[test] - fn map() { - let a = ArcSwap::from_pointee(Cfg { value: 42 }); - let map = a.map(|a: &Cfg| &a.value); - check_static_dispatch_direct(&map); - check_dyn_dispatch_direct(&map); - } - - #[test] - fn map_option_some() { - let a = ArcSwapOption::from_pointee(Cfg { value: 42 }); - let map = a.map(|a: &Option>| a.as_ref().map(|c| &c.value).unwrap()); - check_static_dispatch_direct(&map); - check_dyn_dispatch_direct(&map); - } - - #[test] - fn map_option_none() { - let a = ArcSwapOption::empty(); - let map = a.map(|a: &Option>| a.as_ref().map(|c| &c.value).unwrap_or(&42)); - check_static_dispatch_direct(&map); - check_dyn_dispatch_direct(&map); - } - - #[test] - fn constant() { - let c = Constant(42); - check_static_dispatch_direct(c); - check_dyn_dispatch_direct(&c); - check_static_dispatch_direct(c); - } - - #[test] - fn map_reload() { - let a = ArcSwap::from_pointee(Cfg { value: 0 }); - let map = a.map(|cfg: &Cfg| &cfg.value); - assert_eq!(0, *Access::load(&map)); - a.store(Arc::new(Cfg { value: 42 })); - assert_eq!(42, *Access::load(&map)); - } - - // Compile tests for dynamic access - fn _expect_access(_: impl Access) {} - - fn _dyn_access(x: Box + '_>) { - _expect_access(x) - } - - fn _dyn_access_send(x: Box + '_ + Send>) { - _expect_access(x) - } - - fn _dyn_access_send_sync(x: Box + '_ + Send + Sync>) { - _expect_access(x) - } - - #[test] - #[allow(clippy::arc_with_non_send_sync)] // Whatever, it's tests... - fn double_dyn_access_complex() { - struct Inner { - val: usize, - } - - struct Middle { - inner: Inner, - } - - struct Outer { - middle: Middle, - } - - let outer = Arc::new(ArcSwap::from_pointee(Outer { - middle: Middle { - inner: Inner { val: 42 }, - }, - })); - - let middle: Arc> = - Arc::new(Map::new(outer, |outer: &Outer| &outer.middle)); - let inner: Arc> = - Arc::new(Map::new(middle, |middle: &Middle| &middle.inner)); - // Damn. We have the DynAccess wrapper in scope and need to disambiguate the inner.load() - let guard = Access::load(&inner); - assert_eq!(42, guard.val); - } -} diff --git a/third-party/vendor/arc-swap/src/as_raw.rs b/third-party/vendor/arc-swap/src/as_raw.rs deleted file mode 100644 index f7bb1690..00000000 --- a/third-party/vendor/arc-swap/src/as_raw.rs +++ /dev/null @@ -1,72 +0,0 @@ -use super::{Guard, RefCnt}; - -mod sealed { - pub trait Sealed {} -} - -use self::sealed::Sealed; - -/// A trait describing things that can be turned into a raw pointer. -/// -/// This is just an abstraction of things that can be passed to the -/// [`compare_and_swap`](struct.ArcSwapAny.html#method.compare_and_swap). -/// -/// # Examples -/// -/// ``` -/// use std::ptr; -/// use std::sync::Arc; -/// -/// use arc_swap::ArcSwapOption; -/// -/// let a = Arc::new(42); -/// let shared = ArcSwapOption::from(Some(Arc::clone(&a))); -/// -/// shared.compare_and_swap(&a, Some(Arc::clone(&a))); -/// shared.compare_and_swap(&None::>, Some(Arc::clone(&a))); -/// shared.compare_and_swap(shared.load(), Some(Arc::clone(&a))); -/// shared.compare_and_swap(&shared.load(), Some(Arc::clone(&a))); -/// shared.compare_and_swap(ptr::null(), Some(Arc::clone(&a))); -/// ``` -/// -/// Due to technical limitation, this is not implemented for owned `Arc`/`Option>`, they -/// need to be borrowed. -pub trait AsRaw: Sealed { - /// Converts the value into a raw pointer. - fn as_raw(&self) -> *mut T; -} - -impl<'a, T: RefCnt> Sealed for &'a T {} -impl<'a, T: RefCnt> AsRaw for &'a T { - fn as_raw(&self) -> *mut T::Base { - T::as_ptr(self) - } -} - -impl<'a, T: RefCnt> Sealed for &'a Guard {} -impl<'a, T: RefCnt> AsRaw for &'a Guard { - fn as_raw(&self) -> *mut T::Base { - T::as_ptr(self) - } -} - -impl Sealed for Guard {} -impl AsRaw for Guard { - fn as_raw(&self) -> *mut T::Base { - T::as_ptr(self) - } -} - -impl Sealed for *mut T {} -impl AsRaw for *mut T { - fn as_raw(&self) -> *mut T { - *self - } -} - -impl Sealed for *const T {} -impl AsRaw for *const T { - fn as_raw(&self) -> *mut T { - *self as *mut T - } -} diff --git a/third-party/vendor/arc-swap/src/cache.rs b/third-party/vendor/arc-swap/src/cache.rs deleted file mode 100644 index 61331546..00000000 --- a/third-party/vendor/arc-swap/src/cache.rs +++ /dev/null @@ -1,343 +0,0 @@ -#![deny(unsafe_code)] - -//! Caching handle into the [ArcSwapAny]. -//! -//! The [Cache] keeps a copy of the internal [Arc] for faster access. -//! -//! [Arc]: std::sync::Arc - -use core::ops::Deref; -use core::sync::atomic::Ordering; - -use super::ref_cnt::RefCnt; -use super::strategy::Strategy; -use super::ArcSwapAny; - -/// Generalization of caches providing access to `T`. -/// -/// This abstracts over all kinds of caches that can provide a cheap access to values of type `T`. -/// This is useful in cases where some code doesn't care if the `T` is the whole structure or just -/// a part of it. -/// -/// See the example at [`Cache::map`]. -pub trait Access { - /// Loads the value from cache. - /// - /// This revalidates the value in the cache, then provides the access to the cached value. - fn load(&mut self) -> &T; -} - -/// Caching handle for [`ArcSwapAny`][ArcSwapAny]. -/// -/// Instead of loading the [`Arc`][Arc] on every request from the shared storage, this keeps -/// another copy inside itself. Upon request it only cheaply revalidates it is up to -/// date. If it is, access is significantly faster. If it is stale, the [load_full] is done and the -/// cache value is replaced. Under a read-heavy loads, the measured speedup are 10-25 times, -/// depending on the architecture. -/// -/// There are, however, downsides: -/// -/// * The handle needs to be kept around by the caller (usually, one per thread). This is fine if -/// there's one global `ArcSwapAny`, but starts being tricky with eg. data structures build from -/// them. -/// * As it keeps a copy of the [Arc] inside the cache, the old value may be kept alive for longer -/// period of time ‒ it is replaced by the new value on [load][Cache::load]. You may not want to -/// use this if dropping the old value in timely manner is important (possibly because of -/// releasing large amount of RAM or because of closing file handles). -/// -/// # Examples -/// -/// ```rust -/// # fn do_something(_v: V) { } -/// use std::sync::Arc; -/// use std::sync::atomic::{AtomicBool, Ordering}; -/// -/// use arc_swap::{ArcSwap, Cache}; -/// -/// let shared = Arc::new(ArcSwap::from_pointee(42)); -/// # let mut threads = Vec::new(); -/// let terminate = Arc::new(AtomicBool::new(false)); -/// // Start 10 worker threads... -/// for _ in 0..10 { -/// let mut cache = Cache::new(Arc::clone(&shared)); -/// let terminate = Arc::clone(&terminate); -/// # let thread = -/// std::thread::spawn(move || { -/// // Keep loading it like mad.. -/// while !terminate.load(Ordering::Relaxed) { -/// let value = cache.load(); -/// do_something(value); -/// } -/// }); -/// # threads.push(thread); -/// } -/// shared.store(Arc::new(12)); -/// # terminate.store(true, Ordering::Relaxed); -/// # for thread in threads { thread.join().unwrap() } -/// ``` -/// -/// Another one with using a thread local storage and explicit types: -/// -/// ```rust -/// # use std::sync::Arc; -/// # use std::ops::Deref; -/// # use std::cell::RefCell; -/// # -/// # use arc_swap::ArcSwap; -/// # use arc_swap::cache::Cache; -/// # use once_cell::sync::Lazy; -/// # -/// # #[derive(Debug, Default)] -/// # struct Config; -/// # -/// static CURRENT_CONFIG: Lazy> = Lazy::new(|| ArcSwap::from_pointee(Config::default())); -/// -/// thread_local! { -/// static CACHE: RefCell, Arc>> = RefCell::new(Cache::from(CURRENT_CONFIG.deref())); -/// } -/// -/// CACHE.with(|c| { -/// // * RefCell needed, because load on cache is `&mut`. -/// // * You want to operate inside the `with` ‒ cloning the Arc is comparably expensive as -/// // ArcSwap::load itself and whatever you'd save by the cache would be lost on that. -/// println!("{:?}", c.borrow_mut().load()); -/// }); -/// ``` -/// -/// [Arc]: std::sync::Arc -/// [load_full]: ArcSwapAny::load_full -#[derive(Clone, Debug)] -pub struct Cache { - arc_swap: A, - cached: T, -} - -impl Cache -where - A: Deref>, - T: RefCnt, - S: Strategy, -{ - /// Creates a new caching handle. - /// - /// The parameter is something dereferencing into an [`ArcSwapAny`] (eg. either to [`ArcSwap`] - /// or [`ArcSwapOption`]). That can be [`ArcSwapAny`] itself, but that's not very useful. But - /// it also can be a reference to it or `Arc`, which makes it possible to share the - /// [`ArcSwapAny`] with multiple caches or access it in non-cached way too. - /// - /// [`ArcSwapOption`]: crate::ArcSwapOption - /// [`ArcSwap`]: crate::ArcSwap - pub fn new(arc_swap: A) -> Self { - let cached = arc_swap.load_full(); - Self { arc_swap, cached } - } - - /// Gives access to the (possibly shared) cached [`ArcSwapAny`]. - pub fn arc_swap(&self) -> &A::Target { - &self.arc_swap - } - - /// Loads the currently held value. - /// - /// This first checks if the cached value is up to date. This check is very cheap. - /// - /// If it is up to date, the cached value is simply returned without additional costs. If it is - /// outdated, a load is done on the underlying shared storage. The newly loaded value is then - /// stored in the cache and returned. - #[inline] - pub fn load(&mut self) -> &T { - self.revalidate(); - self.load_no_revalidate() - } - - #[inline] - fn load_no_revalidate(&self) -> &T { - &self.cached - } - - #[inline] - fn revalidate(&mut self) { - let cached_ptr = RefCnt::as_ptr(&self.cached); - // Node: Relaxed here is fine. We do not synchronize any data through this, we already have - // it synchronized in self.cache. We just want to check if it changed, if it did, the - // load_full will be responsible for any synchronization needed. - let shared_ptr = self.arc_swap.ptr.load(Ordering::Relaxed); - if cached_ptr != shared_ptr { - self.cached = self.arc_swap.load_full(); - } - } - - /// Turns this cache into a cache with a projection inside the cached value. - /// - /// You'd use this in case when some part of code needs access to fresh values of `U`, however - /// a bigger structure containing `U` is provided by this cache. The possibility of giving the - /// whole structure to the part of the code falls short in terms of reusability (the part of - /// the code could be used within multiple contexts, each with a bigger different structure - /// containing `U`) and code separation (the code shouldn't needs to know about the big - /// structure). - /// - /// # Warning - /// - /// As the provided `f` is called inside every [`load`][Access::load], this one should be - /// cheap. Most often it is expected to be just a closure taking reference of some inner field. - /// - /// For the same reasons, it should not have side effects and should never panic (these will - /// not break Rust's safety rules, but might produce behaviour you don't expect). - /// - /// # Examples - /// - /// ```rust - /// use arc_swap::ArcSwap; - /// use arc_swap::cache::{Access, Cache}; - /// - /// struct InnerCfg { - /// answer: usize, - /// } - /// - /// struct FullCfg { - /// inner: InnerCfg, - /// } - /// - /// fn use_inner>(cache: &mut A) { - /// let value = cache.load(); - /// println!("The answer is: {}", value.answer); - /// } - /// - /// let full_cfg = ArcSwap::from_pointee(FullCfg { - /// inner: InnerCfg { - /// answer: 42, - /// } - /// }); - /// let cache = Cache::new(&full_cfg); - /// use_inner(&mut cache.map(|full| &full.inner)); - /// - /// let inner_cfg = ArcSwap::from_pointee(InnerCfg { answer: 24 }); - /// let mut inner_cache = Cache::new(&inner_cfg); - /// use_inner(&mut inner_cache); - /// ``` - pub fn map(self, f: F) -> MapCache - where - F: FnMut(&T) -> &U, - { - MapCache { - inner: self, - projection: f, - } - } -} - -impl Access for Cache -where - A: Deref>, - T: Deref::Base> + RefCnt, - S: Strategy, -{ - fn load(&mut self) -> &T::Target { - self.load().deref() - } -} - -impl From for Cache -where - A: Deref>, - T: RefCnt, - S: Strategy, -{ - fn from(arc_swap: A) -> Self { - Self::new(arc_swap) - } -} - -/// An implementation of a cache with a projection into the accessed value. -/// -/// This is the implementation structure for [`Cache::map`]. It can't be created directly and it -/// should be used through the [`Access`] trait. -#[derive(Clone, Debug)] -pub struct MapCache { - inner: Cache, - projection: F, -} - -impl Access for MapCache -where - A: Deref>, - T: RefCnt, - S: Strategy, - F: FnMut(&T) -> &U, -{ - fn load(&mut self) -> &U { - (self.projection)(self.inner.load()) - } -} - -#[cfg(test)] -mod tests { - use alloc::sync::Arc; - - use super::*; - use crate::{ArcSwap, ArcSwapOption}; - - #[test] - fn cached_value() { - let a = ArcSwap::from_pointee(42); - let mut c1 = Cache::new(&a); - let mut c2 = Cache::new(&a); - - assert_eq!(42, **c1.load()); - assert_eq!(42, **c2.load()); - - a.store(Arc::new(43)); - assert_eq!(42, **c1.load_no_revalidate()); - assert_eq!(43, **c1.load()); - } - - #[test] - fn cached_through_arc() { - let a = Arc::new(ArcSwap::from_pointee(42)); - let mut c = Cache::new(Arc::clone(&a)); - assert_eq!(42, **c.load()); - a.store(Arc::new(0)); - drop(a); // A is just one handle, the ArcSwap is kept alive by the cache. - } - - #[test] - fn cache_option() { - let a = ArcSwapOption::from_pointee(42); - let mut c = Cache::new(&a); - - assert_eq!(42, **c.load().as_ref().unwrap()); - a.store(None); - assert!(c.load().is_none()); - } - - struct Inner { - answer: usize, - } - - struct Outer { - inner: Inner, - } - - #[test] - fn map_cache() { - let a = ArcSwap::from_pointee(Outer { - inner: Inner { answer: 42 }, - }); - - let mut cache = Cache::new(&a); - let mut inner = cache.clone().map(|outer| &outer.inner); - let mut answer = cache.clone().map(|outer| &outer.inner.answer); - - assert_eq!(42, cache.load().inner.answer); - assert_eq!(42, inner.load().answer); - assert_eq!(42, *answer.load()); - - a.store(Arc::new(Outer { - inner: Inner { answer: 24 }, - })); - - assert_eq!(24, cache.load().inner.answer); - assert_eq!(24, inner.load().answer); - assert_eq!(24, *answer.load()); - } -} diff --git a/third-party/vendor/arc-swap/src/compile_fail_tests.rs b/third-party/vendor/arc-swap/src/compile_fail_tests.rs deleted file mode 100644 index c56bbb79..00000000 --- a/third-party/vendor/arc-swap/src/compile_fail_tests.rs +++ /dev/null @@ -1,93 +0,0 @@ -// The doc tests allow us to do a compile_fail test, which is cool and what we want, but we don't -// want to expose this in the docs, so we use a private struct for that reason. -// -// Note we also bundle one that *does* compile with each, just to make sure they don't silently -// not-compile by some different reason. -//! ```rust,compile_fail -//! let shared = arc_swap::ArcSwap::from_pointee(std::cell::Cell::new(42)); -//! std::thread::spawn(|| { -//! drop(shared); -//! }); -//! ``` -//! -//! ```rust -//! let shared = arc_swap::ArcSwap::from_pointee(42); -//! std::thread::spawn(|| { -//! drop(shared); -//! }) -//! .join() -//! .unwrap(); -//! ``` -//! -//! ```rust,compile_fail -//! let shared = arc_swap::ArcSwap::from_pointee(std::cell::Cell::new(42)); -//! let guard = shared.load(); -//! std::thread::spawn(|| { -//! drop(guard); -//! }); -//! ``` -//! -//! ```rust -//! let shared = arc_swap::ArcSwap::from_pointee(42); -//! let guard = shared.load(); -//! std::thread::spawn(|| { -//! drop(guard); -//! }) -//! .join() -//! .unwrap(); -//! ``` -//! -//! ```rust,compile_fail -//! let shared = arc_swap::ArcSwap::from_pointee(std::cell::Cell::new(42)); -//! crossbeam_utils::thread::scope(|scope| { -//! scope.spawn(|_| { -//! let _ = &shared; -//! }); -//! }).unwrap(); -//! ``` -//! -//! ```rust -//! let shared = arc_swap::ArcSwap::from_pointee(42); -//! crossbeam_utils::thread::scope(|scope| { -//! scope.spawn(|_| { -//! let _ = &shared; -//! }); -//! }).unwrap(); -//! ``` -//! -//! ```rust,compile_fail -//! let shared = arc_swap::ArcSwap::from_pointee(std::cell::Cell::new(42)); -//! let guard = shared.load(); -//! crossbeam_utils::thread::scope(|scope| { -//! scope.spawn(|_| { -//! let _ = &guard; -//! }); -//! }).unwrap(); -//! ``` -//! -//! ```rust -//! let shared = arc_swap::ArcSwap::from_pointee(42); -//! let guard = shared.load(); -//! crossbeam_utils::thread::scope(|scope| { -//! scope.spawn(|_| { -//! let _ = &guard; -//! }); -//! }).unwrap(); -//! ``` -//! -//! See that `ArcSwapAny` really isn't Send. -//! ```rust -//! use std::sync::Arc; -//! use arc_swap::ArcSwapAny; -//! -//! let a: ArcSwapAny> = ArcSwapAny::new(Arc::new(42)); -//! std::thread::spawn(move || drop(a)).join().unwrap(); -//! ``` -//! -//! ```rust,compile_fail -//! use std::rc::Rc; -//! use arc_swap::ArcSwapAny; -//! -//! let a: ArcSwapAny> = ArcSwapAny::new(Rc::new(42)); -//! std::thread::spawn(move || drop(a)); -//! ``` diff --git a/third-party/vendor/arc-swap/src/debt/fast.rs b/third-party/vendor/arc-swap/src/debt/fast.rs deleted file mode 100644 index 8e71e388..00000000 --- a/third-party/vendor/arc-swap/src/debt/fast.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! The fast slots for the primary strategy. -//! -//! They are faster, but fallible (in case the slots run out or if there's a collision with a -//! writer thread, this gives up and falls back to secondary strategy). -//! -//! They are based on hazard pointer ideas. To acquire one, the pointer is loaded, stored in the -//! slot and the debt is confirmed by loading it again and checking it is the same. -//! -//! # Orderings -//! -//! We ensure just one thing here. Since we do both the acquisition of the slot and the exchange of -//! the pointer in the writer with SeqCst, we are guaranteed to either see the change in case it -//! hits somewhere in between the two reads of the pointer, or to have successfully acquired it -//! before the change and before any cleanup of the old pointer happened (in which case we know the -//! writer will see our debt). - -use core::cell::Cell; -use core::slice::Iter; -use core::sync::atomic::Ordering::*; - -use super::Debt; - -const DEBT_SLOT_CNT: usize = 8; - -/// Thread-local information for the [`Slots`] -#[derive(Default)] -pub(super) struct Local { - // The next slot in round-robin rotation. Heuristically tries to balance the load across them - // instead of having all of them stuffed towards the start of the array which gets - // unsuccessfully iterated through every time. - offset: Cell, -} - -/// Bunch of fast debt slots. -#[derive(Default)] -pub(super) struct Slots([Debt; DEBT_SLOT_CNT]); - -impl Slots { - /// Try to allocate one slot and get the pointer in it. - /// - /// Fails if there are no free slots. - #[inline] - pub(super) fn get_debt(&self, ptr: usize, local: &Local) -> Option<&Debt> { - // Trick with offsets: we rotate through the slots (save the value from last time) - // so successive leases are likely to succeed on the first attempt (or soon after) - // instead of going through the list of already held ones. - let offset = local.offset.get(); - let len = self.0.len(); - for i in 0..len { - let i = (i + offset) % len; - // Note: the indexing check is almost certainly optimised out because the len - // is used above. And using .get_unchecked was actually *slower*. - let slot = &self.0[i]; - if slot.0.load(Relaxed) == Debt::NONE { - // We are allowed to split into the check and acquiring the debt. That's because we - // are the only ones allowed to change NONE to something else. But we still need a - // read-write operation wit SeqCst on it :-( - let old = slot.0.swap(ptr, SeqCst); - debug_assert_eq!(Debt::NONE, old); - local.offset.set(i + 1); - return Some(&self.0[i]); - } - } - None - } -} - -impl<'a> IntoIterator for &'a Slots { - type Item = &'a Debt; - - type IntoIter = Iter<'a, Debt>; - - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} diff --git a/third-party/vendor/arc-swap/src/debt/helping.rs b/third-party/vendor/arc-swap/src/debt/helping.rs deleted file mode 100644 index af335322..00000000 --- a/third-party/vendor/arc-swap/src/debt/helping.rs +++ /dev/null @@ -1,334 +0,0 @@ -//! Slots and global/thread local data for the Helping strategy. -//! -//! This is inspired (but not an exact copy) of -//! . The debts are mostly -//! copies of the ones used by the hybrid strategy, but modified a bit. Just like in the hybrid -//! strategy, in case the slots run out or when the writer updates the value, the debts are paid by -//! incrementing the ref count (which is a little slower, but still wait-free/lock-free and still -//! in order of nanoseconds). -//! -//! ## Reader, the fast path -//! -//! * Publish an active address ‒ the address we'll be loading stuff from. -//! * Puts a generation into the control. -//! * Loads the pointer and puts it to the debt slot. -//! * Confirms by CaS-replacing the generation back to idle state. -//! -//! * Later, we pay it back by CaS-replacing it with the NO_DEPT (like any other slot). -//! -//! ## Writer, the non-colliding path -//! -//! * Replaces the pointer in the storage. -//! * The writer walks over all debts. It pays each debt that it is concerned with by bumping the -//! reference and replacing the dept with NO_DEPT. The relevant reader will fail in the CaS -//! (either because it finds NO_DEPT or other pointer in there) and knows the reference was -//! bumped, so it needs to decrement it. Note that it is possible that someone also reuses the -//! slot for the _same_ pointer. In that case that reader will set it to NO_DEPT and the newer -//! reader will have a pre-paid debt, which is fine. -//! -//! ## The collision path -//! -//! The reservation of a slot is not atomic, therefore a writer can observe the reservation in -//! progress. But it doesn't want to wait for it to complete (it wants to be lock-free, which means -//! it needs to be able to resolve the situation on its own). -//! -//! The way it knows it is in progress of the reservation is by seeing a generation in there (it has -//! a distinct tag). In that case it'll try to: -//! -//! * First verify that the reservation is being done for the same address it modified, by reading -//! and re-confirming the active_addr slot corresponding to the currently handled node. If it is -//! for some other address, the writer doesn't have to be concerned and proceeds to the next slot. -//! * It does a full load. That is fine, because the writer must be on a different thread than the -//! reader and therefore there is at least one free slot. Full load means paying the debt right -//! away by incrementing the reference count. -//! * Then it tries to pass the already fully protected/paid pointer to the reader. It writes it to -//! an envelope and CaS-replaces it into the control, instead of the generation (if it fails, -//! someone has been faster and it rolls back). We need the envelope because the pointer itself -//! doesn't have to be aligned to 4 bytes and we need the space for tags to distinguish the types -//! of info in control; we can ensure the envelope is). -//! * The reader then finds the generation got replaced by a pointer to the envelope and uses that -//! pointer inside the envelope. It aborts its own debt. This effectively exchanges the envelopes -//! between the threads so each one has an envelope ready for future. -//! -//! ## ABA protection -//! -//! The generation as pre-reserving the slot allows the writer to make sure it is offering the -//! loaded pointer to the same reader and that the read value is new enough (and of the same type). -//! -//! This solves the general case, but there's also much less frequent but theoretical ABA problem -//! that could lead to UB, if left unsolved: -//! -//! * There is a collision on generation G. -//! * The writer loads a pointer, bumps it. -//! * In the meantime, all the 2^30 or 2^62 generations (depending on the usize width) generations -//! wrap around. -//! * The writer stores the outdated and possibly different-typed pointer in there and the reader -//! uses it. -//! -//! To mitigate that, every time the counter overflows we take the current node and un-assign it -//! from our current thread. We mark it as in "cooldown" and let it in there until there are no -//! writers messing with that node any more (if they are not on the node, they can't experience the -//! ABA problem on it). After that, we are allowed to use it again. -//! -//! This doesn't block the reader, it'll simply find *a* node next time ‒ this one, or possibly a -//! different (or new) one. -//! -//! # Orderings -//! -//! The linked lists/nodes are already provided for us. So we just need to make sure the debt -//! juggling is done right. We assume that the local node is ours to write to (others have only -//! limited right to write to certain fields under certain conditions) and that we are counted into -//! active writers while we dig through it on the writer end. -//! -//! We use SeqCst on a read-write operation both here at the very start of the sequence (storing -//! the generation into the control) and in the writer on the actual pointer. That establishes a -//! relation of what has happened first. -//! -//! After that we split the time into segments by read-write operations with AcqRel read-write -//! operations on the control. There's just one control in play for both threads so we don't need -//! SeqCst and the segments are understood by both the same way. The writer can sometimes use only -//! load-Acquire on that, because it needs to only read from data written by the reader. It'll -//! always see data from at least the segment before the observed control value and uses CaS to -//! send the results back, so it can't go into the past. -//! -//! There are two little gotchas: -//! -//! * When we read the address we should be loading from, we need to give up if the address does -//! not match (we can't simply load from there, because it can be dangling by that point and we -//! don't know its type, so we need to use our address for all loading ‒ and we just check they -//! match). If we give up, we don't do that CaS into control, therefore we could have given up on -//! newer address than the control we have read. For that reason, the address is also stored by -//! reader with Release and we read it with Acquire, which'll bring an up to date version of -//! control into our thread ‒ and we re-read that one to confirm the address is indeed between -//! two same values holding the generation, therefore corresponding to it. -//! * The destructor doesn't have a SeqCst in the writer, because there was no write in there. -//! That's OK. We need to ensure there are no new readers after the "change" we confirm in the -//! writer and that change is the destruction ‒ by that time, the destroying thread has exclusive -//! ownership and therefore there can be no new readers. - -use core::cell::Cell; -use core::ptr; -use core::sync::atomic::Ordering::*; -use core::sync::atomic::{AtomicPtr, AtomicUsize}; - -use super::Debt; -use crate::RefCnt; - -pub const REPLACEMENT_TAG: usize = 0b01; -pub const GEN_TAG: usize = 0b10; -pub const TAG_MASK: usize = 0b11; -pub const IDLE: usize = 0; - -/// Thread local data for the helping strategy. -#[derive(Default)] -pub(super) struct Local { - // The generation counter. - generation: Cell, -} - -// Make sure the pointers have 2 empty bits. Always. -#[derive(Default)] -#[repr(align(4))] -struct Handover(AtomicUsize); - -/// The slots for the helping strategy. -pub(super) struct Slots { - /// The control structure of the slot. - /// - /// Different threads signal what stage they are in in there. It can contain: - /// - /// * `IDLE` (nothing is happening, and there may or may not be an active debt). - /// * a generation, tagged with GEN_TAG. The reader is trying to acquire a slot right now and a - /// writer might try to help out. - /// * A replacement pointer, tagged with REPLACEMENT_TAG. This pointer points to an Handover, - /// containing an already protected value, provided by the writer for the benefit of the - /// reader. The reader should abort its own debt and use this instead. This indirection - /// (storing pointer to the envelope with the actual pointer) is to make sure there's a space - /// for the tag ‒ there is no guarantee the real pointer is aligned to at least 4 bytes, we - /// can however force that for the Handover type. - control: AtomicUsize, - /// A possibly active debt. - slot: Debt, - /// If there's a generation in control, this signifies what address the reader is trying to - /// load from. - active_addr: AtomicUsize, - /// A place where a writer can put a replacement value. - /// - /// Note that this is simply an allocation, and every participating slot contributes one, but - /// they may be passed around through the lifetime of the program. It is not accessed directly, - /// but through the space_offer thing. - /// - handover: Handover, - /// A pointer to a handover envelope this node currently owns. - /// - /// A writer makes a switch of its and readers handover when successfully storing a replacement - /// in the control. - space_offer: AtomicPtr, -} - -impl Default for Slots { - fn default() -> Self { - Slots { - control: AtomicUsize::new(IDLE), - slot: Debt::default(), - // Doesn't matter yet - active_addr: AtomicUsize::new(0), - // Also doesn't matter - handover: Handover::default(), - // Here we would like it to point to our handover. But for that we need to be in place - // in RAM (effectively pinned, though we use older Rust than Pin, possibly?), so not - // yet. See init(). - space_offer: AtomicPtr::new(ptr::null_mut()), - } - } -} - -impl Slots { - pub(super) fn slot(&self) -> &Debt { - &self.slot - } - - pub(super) fn get_debt(&self, ptr: usize, local: &Local) -> (usize, bool) { - // Incrementing by 4 ensures we always have enough space for 2 bit of tags. - let gen = local.generation.get().wrapping_add(4); - debug_assert_eq!(gen & GEN_TAG, 0); - local.generation.set(gen); - // Signal the caller that the node should be sent to a cooldown. - let discard = gen == 0; - let gen = gen | GEN_TAG; - // We will sync by the write to the control. But we also sync the value of the previous - // generation/released slot. That way we may re-confirm in the writer that the reader is - // not in between here and the compare_exchange below with a stale gen (eg. if we are in - // here, the re-confirm there will load the NO_DEPT and we are fine). - self.active_addr.store(ptr, SeqCst); - - // We are the only ones allowed to do the IDLE -> * transition and we never leave it in - // anything else after an transaction, so this is OK. But we still need a load-store SeqCst - // operation here to form a relation between this and the store of the actual pointer in - // the writer thread :-(. - let prev = self.control.swap(gen, SeqCst); - debug_assert_eq!(IDLE, prev, "Left control in wrong state"); - - (gen, discard) - } - - pub(super) fn help(&self, who: &Self, storage_addr: usize, replacement: &R) - where - T: RefCnt, - R: Fn() -> T, - { - debug_assert_eq!(IDLE, self.control.load(Relaxed)); - // Also acquires the auxiliary data in other variables. - let mut control = who.control.load(SeqCst); - loop { - match control & TAG_MASK { - // Nothing to help with - IDLE if control == IDLE => break, - // Someone has already helped out with that, so we have nothing to do here - REPLACEMENT_TAG => break, - // Something is going on, let's have a better look. - GEN_TAG => { - debug_assert!( - !ptr::eq(self, who), - "Refusing to help myself, makes no sense" - ); - // Get the address that other thread is trying to load from. By that acquire, - // we also sync the control into our thread once more and reconfirm that the - // value of the active_addr is in between two same instances, therefore up to - // date to it. - let active_addr = who.active_addr.load(SeqCst); - if active_addr != storage_addr { - // Acquire for the same reason as on the top. - let new_control = who.control.load(SeqCst); - if new_control == control { - // The other thread is doing something, but to some other ArcSwap, so - // we don't care. Cool, done. - break; - } else { - // The control just changed under our hands, we don't know what to - // trust, so retry. - control = new_control; - continue; - } - } - - // Now we know this work is for us. Try to create a replacement and offer it. - // This actually does a full-featured load under the hood, but we are currently - // idle and the load doesn't re-enter write, so that's all fine. - let replacement = replacement(); - let replace_addr = T::as_ptr(&replacement) as usize; - // If we succeed in helping the other thread, we take their empty space in - // return for us that we pass to them. It's already there, the value is synced - // to us by Acquire on control. - let their_space = who.space_offer.load(SeqCst); - // Relaxed is fine, our own thread and nobody but us writes in here. - let my_space = self.space_offer.load(SeqCst); - // Relaxed is fine, we'll sync by the next compare-exchange. If we don't, the - // value won't ever be read anyway. - unsafe { - (*my_space).0.store(replace_addr, SeqCst); - } - // Ensured by the align annotation at the type. - assert_eq!(my_space as usize & TAG_MASK, 0); - let space_addr = (my_space as usize) | REPLACEMENT_TAG; - // Acquire on failure -> same reason as at the top, reading the value. - // Release on success -> we send data to that thread through here. Must be - // AcqRel, because success must be superset of failure. Also, load to get their - // space (it won't have changed, it does when the control is set to IDLE). - match who - .control - .compare_exchange(control, space_addr, SeqCst, SeqCst) - { - Ok(_) => { - // We have successfully sent our replacement out (Release) and got - // their space in return (Acquire on that load above). - self.space_offer.store(their_space, SeqCst); - // The ref count went with it, so forget about it here. - T::into_ptr(replacement); - // We have successfully helped out, so we are done. - break; - } - Err(new_control) => { - // Something has changed in between. Let's try again, nothing changed - // (the replacement will get dropped at the end of scope, we didn't do - // anything with the spaces, etc. - control = new_control; - } - } - } - _ => unreachable!("Invalid control value {:X}", control), - } - } - } - - pub(super) fn init(&mut self) { - *self.space_offer.get_mut() = &mut self.handover; - } - - pub(super) fn confirm(&self, gen: usize, ptr: usize) -> Result<(), usize> { - // Put the slot there and consider it acquire of a „lock“. For that we need swap, not store - // only (we need Acquire and Acquire works only on loads). Release is to make sure control - // is observable by the other thread (but that's probably not necessary anyway?) - let prev = self.slot.0.swap(ptr, SeqCst); - debug_assert_eq!(Debt::NONE, prev); - - // Confirm by writing to the control (or discover that we got helped). We stop anyone else - // from helping by setting it to IDLE. - let control = self.control.swap(IDLE, SeqCst); - if control == gen { - // Nobody interfered, we have our debt in place and can proceed. - Ok(()) - } else { - // Someone put a replacement in there. - debug_assert_eq!(control & TAG_MASK, REPLACEMENT_TAG); - let handover = (control & !TAG_MASK) as *mut Handover; - let replacement = unsafe { &*handover }.0.load(SeqCst); - // Make sure we advertise the right envelope when we set it to generation next time. - self.space_offer.store(handover, SeqCst); - // Note we've left the debt in place. The caller should pay it back (without ever - // taking advantage of it) to make sure any extra is actually dropped (it is possible - // someone provided the replacement *and* paid the debt and we need just one of them). - Err(replacement) - } - } -} diff --git a/third-party/vendor/arc-swap/src/debt/list.rs b/third-party/vendor/arc-swap/src/debt/list.rs deleted file mode 100644 index afb383e3..00000000 --- a/third-party/vendor/arc-swap/src/debt/list.rs +++ /dev/null @@ -1,371 +0,0 @@ -//! A linked list of debt nodes. -//! -//! A node may or may not be owned by a thread. Reader debts are allocated in its owned node, -//! writer walks everything (but may also use some owned values). -//! -//! The list is prepend-only ‒ if thread dies, the node lives on (and can be claimed by another -//! thread later on). This makes the implementation much simpler, since everything here is -//! `'static` and we don't have to care about knowing when to free stuff. -//! -//! The nodes contain both the fast primary slots and a secondary fallback ones. -//! -//! # Synchronization -//! -//! We synchronize several things here. -//! -//! The addition of nodes is synchronized through the head (Load on each read, AcqReal on each -//! attempt to add another node). Note that certain parts never change after that (they aren't even -//! atomic) and other things that do change take care of themselves (the debt slots have their own -//! synchronization, etc). -//! -//! The ownership is acquire-release lock pattern. -//! -//! Similar, the counting of active writers is an acquire-release lock pattern. -//! -//! We also do release-acquire "send" from the start-cooldown to check-cooldown to make sure we see -//! at least as up to date value of the writers as when the cooldown started. That we if we see 0, -//! we know it must have happened since then. - -use core::cell::Cell; -use core::ptr; -use core::slice::Iter; -use core::sync::atomic::Ordering::*; -use core::sync::atomic::{AtomicPtr, AtomicUsize}; - -#[cfg(feature = "experimental-thread-local")] -use core::cell::OnceCell; - -use alloc::boxed::Box; - -use super::fast::{Local as FastLocal, Slots as FastSlots}; -use super::helping::{Local as HelpingLocal, Slots as HelpingSlots}; -use super::Debt; -use crate::RefCnt; - -const NODE_UNUSED: usize = 0; -const NODE_USED: usize = 1; -const NODE_COOLDOWN: usize = 2; - -/// The head of the debt linked list. -static LIST_HEAD: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - -pub struct NodeReservation<'a>(&'a Node); - -impl Drop for NodeReservation<'_> { - fn drop(&mut self) { - self.0.active_writers.fetch_sub(1, Release); - } -} - -/// One thread-local node for debts. -#[repr(C, align(64))] -pub(crate) struct Node { - fast: FastSlots, - helping: HelpingSlots, - in_use: AtomicUsize, - // Next node in the list. - // - // It is a pointer because we touch it before synchronization (we don't _dereference_ it before - // synchronization, only manipulate the pointer itself). That is illegal according to strict - // interpretation of the rules by MIRI on references. - next: *const Node, - active_writers: AtomicUsize, -} - -impl Default for Node { - fn default() -> Self { - Node { - fast: FastSlots::default(), - helping: HelpingSlots::default(), - in_use: AtomicUsize::new(NODE_USED), - next: ptr::null(), - active_writers: AtomicUsize::new(0), - } - } -} - -impl Node { - /// Goes through the debt linked list. - /// - /// This traverses the linked list, calling the closure on each node. If the closure returns - /// `Some`, it terminates with that value early, otherwise it runs to the end. - pub(crate) fn traverse Option>(mut f: F) -> Option { - // Acquire ‒ we want to make sure we read the correct version of data at the end of the - // pointer. Any write to the DEBT_HEAD is with Release. - // - // Furthermore, we need to see the newest version of the list in case we examine the debts - // - if a new one is added recently, we don't want a stale read -> SeqCst. - // - // Note that the other pointers in the chain never change and are *ordinary* pointers. The - // whole linked list is synchronized through the head. - let mut current = unsafe { LIST_HEAD.load(SeqCst).as_ref() }; - while let Some(node) = current { - let result = f(node); - if result.is_some() { - return result; - } - current = unsafe { node.next.as_ref() }; - } - None - } - - /// Put the current thread node into cooldown - fn start_cooldown(&self) { - // Trick: Make sure we have an up to date value of the active_writers in this thread, so we - // can properly release it below. - let _reservation = self.reserve_writer(); - assert_eq!(NODE_USED, self.in_use.swap(NODE_COOLDOWN, Release)); - } - - /// Perform a cooldown if the node is ready. - /// - /// See the ABA protection at the [helping]. - fn check_cooldown(&self) { - // Check if the node is in cooldown, for two reasons: - // * Skip most of nodes fast, without dealing with them. - // * More importantly, sync the value of active_writers to be at least the value when the - // cooldown started. That way we know the 0 we observe happened some time after - // start_cooldown. - if self.in_use.load(Acquire) == NODE_COOLDOWN { - // The rest can be nicely relaxed ‒ no memory is being synchronized by these - // operations. We just see an up to date 0 and allow someone (possibly us) to claim the - // node later on. - if self.active_writers.load(Relaxed) == 0 { - let _ = self - .in_use - .compare_exchange(NODE_COOLDOWN, NODE_UNUSED, Relaxed, Relaxed); - } - } - } - - /// Mark this node that a writer is currently playing with it. - pub fn reserve_writer(&self) -> NodeReservation { - self.active_writers.fetch_add(1, Acquire); - NodeReservation(self) - } - - /// "Allocate" a node. - /// - /// Either a new one is created, or previous one is reused. The node is claimed to become - /// in_use. - fn get() -> &'static Self { - // Try to find an unused one in the chain and reuse it. - Self::traverse(|node| { - node.check_cooldown(); - if node - .in_use - // We claim a unique control over the generation and the right to write to slots if - // they are NO_DEPT - .compare_exchange(NODE_UNUSED, NODE_USED, SeqCst, Relaxed) - .is_ok() - { - Some(node) - } else { - None - } - }) - // If that didn't work, create a new one and prepend to the list. - .unwrap_or_else(|| { - let node = Box::leak(Box::::default()); - node.helping.init(); - // We don't want to read any data in addition to the head, Relaxed is fine - // here. - // - // We do need to release the data to others, but for that, we acquire in the - // compare_exchange below. - let mut head = LIST_HEAD.load(Relaxed); - loop { - node.next = head; - if let Err(old) = LIST_HEAD.compare_exchange_weak( - head, node, - // We need to release *the whole chain* here. For that, we need to - // acquire it first. - // - // SeqCst because we need to make sure it is properly set "before" we do - // anything to the debts. - SeqCst, Relaxed, // Nothing changed, go next round of the loop. - ) { - head = old; - } else { - return node; - } - } - }) - } - - /// Iterate over the fast slots. - pub(crate) fn fast_slots(&self) -> Iter { - self.fast.into_iter() - } - - /// Access the helping slot. - pub(crate) fn helping_slot(&self) -> &Debt { - self.helping.slot() - } -} - -/// A wrapper around a node pointer, to un-claim the node on thread shutdown. -pub(crate) struct LocalNode { - /// Node for this thread, if any. - /// - /// We don't necessarily have to own one, but if we don't, we'll get one before the first use. - node: Cell>, - - /// Thread-local data for the fast slots. - fast: FastLocal, - - /// Thread local data for the helping strategy. - helping: HelpingLocal, -} - -impl LocalNode { - #[cfg(not(feature = "experimental-thread-local"))] - pub(crate) fn with R>(f: F) -> R { - let f = Cell::new(Some(f)); - THREAD_HEAD - .try_with(|head| { - if head.node.get().is_none() { - head.node.set(Some(Node::get())); - } - let f = f.take().unwrap(); - f(head) - }) - // During the application shutdown, the thread local storage may be already - // deallocated. In that case, the above fails but we still need something. So we just - // find or allocate a node and use it just once. - // - // Note that the situation should be very very rare and not happen often, so the slower - // performance doesn't matter that much. - .unwrap_or_else(|_| { - let tmp_node = LocalNode { - node: Cell::new(Some(Node::get())), - fast: FastLocal::default(), - helping: HelpingLocal::default(), - }; - let f = f.take().unwrap(); - f(&tmp_node) - // Drop of tmp_node -> sends the node we just used into cooldown. - }) - } - - #[cfg(feature = "experimental-thread-local")] - pub(crate) fn with R>(f: F) -> R { - let thread_head = THREAD_HEAD.get_or_init(|| LocalNode { - node: Cell::new(None), - fast: FastLocal::default(), - helping: HelpingLocal::default(), - }); - if thread_head.node.get().is_none() { - thread_head.node.set(Some(Node::get())); - } - f(&thread_head) - } - - /// Creates a new debt. - /// - /// This stores the debt of the given pointer (untyped, casted into an usize) and returns a - /// reference to that slot, or gives up with `None` if all the slots are currently full. - #[inline] - pub(crate) fn new_fast(&self, ptr: usize) -> Option<&'static Debt> { - let node = &self.node.get().expect("LocalNode::with ensures it is set"); - debug_assert_eq!(node.in_use.load(Relaxed), NODE_USED); - node.fast.get_debt(ptr, &self.fast) - } - - /// Initializes a helping slot transaction. - /// - /// Returns the generation (with tag). - pub(crate) fn new_helping(&self, ptr: usize) -> usize { - let node = &self.node.get().expect("LocalNode::with ensures it is set"); - debug_assert_eq!(node.in_use.load(Relaxed), NODE_USED); - let (gen, discard) = node.helping.get_debt(ptr, &self.helping); - if discard { - // Too many generations happened, make sure the writers give the poor node a break for - // a while so they don't observe the generation wrapping around. - node.start_cooldown(); - self.node.take(); - } - gen - } - - /// Confirm the helping transaction. - /// - /// The generation comes from previous new_helping. - /// - /// Will either return a debt with the pointer, or a debt to pay and a replacement (already - /// protected) address. - pub(crate) fn confirm_helping( - &self, - gen: usize, - ptr: usize, - ) -> Result<&'static Debt, (&'static Debt, usize)> { - let node = &self.node.get().expect("LocalNode::with ensures it is set"); - debug_assert_eq!(node.in_use.load(Relaxed), NODE_USED); - let slot = node.helping_slot(); - node.helping - .confirm(gen, ptr) - .map(|()| slot) - .map_err(|repl| (slot, repl)) - } - - /// The writer side of a helping slot. - /// - /// This potentially helps the `who` node (uses self as the local node, which must be - /// different) by loading the address that one is trying to load. - pub(super) fn help(&self, who: &Node, storage_addr: usize, replacement: &R) - where - T: RefCnt, - R: Fn() -> T, - { - let node = &self.node.get().expect("LocalNode::with ensures it is set"); - debug_assert_eq!(node.in_use.load(Relaxed), NODE_USED); - node.helping.help(&who.helping, storage_addr, replacement) - } -} - -impl Drop for LocalNode { - fn drop(&mut self) { - if let Some(node) = self.node.get() { - // Release - syncing writes/ownership of this Node - node.start_cooldown(); - } - } -} - -#[cfg(not(feature = "experimental-thread-local"))] -thread_local! { - /// A debt node assigned to this thread. - static THREAD_HEAD: LocalNode = LocalNode { - node: Cell::new(None), - fast: FastLocal::default(), - helping: HelpingLocal::default(), - }; -} - -#[cfg(feature = "experimental-thread-local")] -#[thread_local] -/// A debt node assigned to this thread. -static THREAD_HEAD: OnceCell = OnceCell::new(); - -#[cfg(test)] -mod tests { - use super::*; - - impl Node { - fn is_empty(&self) -> bool { - self.fast_slots() - .chain(core::iter::once(self.helping_slot())) - .all(|d| d.0.load(Relaxed) == Debt::NONE) - } - - fn get_thread() -> &'static Self { - LocalNode::with(|h| h.node.get().unwrap()) - } - } - - /// A freshly acquired thread local node is empty. - #[test] - fn new_empty() { - assert!(Node::get_thread().is_empty()); - } -} diff --git a/third-party/vendor/arc-swap/src/debt/mod.rs b/third-party/vendor/arc-swap/src/debt/mod.rs deleted file mode 100644 index 9eddc60c..00000000 --- a/third-party/vendor/arc-swap/src/debt/mod.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! Debt handling. -//! -//! A debt is a reference count of a smart pointer that is owed. This module provides a lock-free -//! storage for debts. -//! -//! Each thread has its own node with bunch of slots. Only that thread can allocate debts in there, -//! but others are allowed to inspect and pay them. The nodes form a linked list for the reason of -//! inspection. The nodes are never removed (even after the thread terminates), but if the thread -//! gives it up, another (new) thread can claim it. -//! -//! The writers walk the whole chain and pay the debts (by bumping the ref counts) of the just -//! removed pointer. -//! -//! Each node has some fast (but fallible) nodes and a fallback node, with different algorithms to -//! claim them (see the relevant submodules). - -use core::sync::atomic::AtomicUsize; -use core::sync::atomic::Ordering::*; - -pub(crate) use self::list::{LocalNode, Node}; -use super::RefCnt; - -mod fast; -mod helping; -mod list; - -/// One debt slot. -/// -/// It may contain an „owed“ reference count. -#[derive(Debug)] -pub(crate) struct Debt(pub(crate) AtomicUsize); - -impl Debt { - /// The value of pointer `3` should be pretty safe, for two reasons: - /// - /// * It's an odd number, but the pointers we have are likely aligned at least to the word size, - /// because the data at the end of the `Arc` has the counters. - /// * It's in the very first page where NULL lives, so it's not mapped. - pub(crate) const NONE: usize = 0b11; -} - -impl Default for Debt { - fn default() -> Self { - Debt(AtomicUsize::new(Self::NONE)) - } -} - -impl Debt { - /// Tries to pay the given debt. - /// - /// If the debt is still there, for the given pointer, it is paid and `true` is returned. If it - /// is empty or if there's some other pointer, it is not paid and `false` is returned, meaning - /// the debt was paid previously by someone else. - /// - /// # Notes - /// - /// * It is possible that someone paid the debt and then someone else put a debt for the same - /// pointer in there. This is fine, as we'll just pay the debt for that someone else. - /// * This relies on the fact that the same pointer must point to the same object and - /// specifically to the same type ‒ the caller provides the type, it's destructor, etc. - /// * It also relies on the fact the same thing is not stuffed both inside an `Arc` and `Rc` or - /// something like that, but that sounds like a reasonable assumption. Someone storing it - /// through `ArcSwap` and someone else with `ArcSwapOption` will work. - #[inline] - pub(crate) fn pay(&self, ptr: *const T::Base) -> bool { - self.0 - // If we don't change anything because there's something else, Relaxed is fine. - // - // The Release works as kind of Mutex. We make sure nothing from the debt-protected - // sections leaks below this point. - // - // Note that if it got paid already, it is inside the reference count. We don't - // necessarily observe that increment, but whoever destroys the pointer *must* see the - // up to date value, with all increments already counted in (the Arc takes care of that - // part). - .compare_exchange(ptr as usize, Self::NONE, Release, Relaxed) - .is_ok() - } - - /// Pays all the debts on the given pointer and the storage. - pub(crate) fn pay_all(ptr: *const T::Base, storage_addr: usize, replacement: R) - where - T: RefCnt, - R: Fn() -> T, - { - LocalNode::with(|local| { - let val = unsafe { T::from_ptr(ptr) }; - // Pre-pay one ref count that can be safely put into a debt slot to pay it. - T::inc(&val); - - Node::traverse::<(), _>(|node| { - // Make the cooldown trick know we are poking into this node. - let _reservation = node.reserve_writer(); - - local.help(node, storage_addr, &replacement); - - let all_slots = node - .fast_slots() - .chain(core::iter::once(node.helping_slot())); - for slot in all_slots { - // Note: Release is enough even here. That makes sure the increment is - // visible to whoever might acquire on this slot and can't leak below this. - // And we are the ones doing decrements anyway. - if slot.pay::(ptr) { - // Pre-pay one more, for another future slot - T::inc(&val); - } - } - - None - }); - // Implicit dec by dropping val in here, pair for the above - }) - } -} - -#[cfg(test)] -mod tests { - use alloc::sync::Arc; - - /// Checks the assumption that arcs to ZSTs have different pointer values. - #[test] - fn arc_zst() { - struct A; - struct B; - - let a = Arc::new(A); - let b = Arc::new(B); - - let aref: &A = &a; - let bref: &B = &b; - - let aptr = aref as *const _ as usize; - let bptr = bref as *const _ as usize; - assert_ne!(aptr, bptr); - } -} diff --git a/third-party/vendor/arc-swap/src/docs/internal.rs b/third-party/vendor/arc-swap/src/docs/internal.rs deleted file mode 100644 index f5ee0011..00000000 --- a/third-party/vendor/arc-swap/src/docs/internal.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! Internal details. -//! -//! While the other parts of documentation are useful to users of the crate, this part is probably -//! helpful only if you want to look into the code or are curious about how it works internally. -//! -//! Also note that any of these details may change in future versions and are not part of the -//! stability guarantees. Don't rely on anything here. -//! -//! # Storing the [`Arc`]. -//! -//! The [`Arc`] can be turned into a raw pointer and back. This is abstracted by the [`RefCnt`] -//! trait and it is technically possible to implement it for custom types (this crate also -//! implements it for [`Rc`] and [`Weak`], though the actual usefulness of these is a bit -//! questionable). -//! -//! The raw pointer is stored inside an [`AtomicPtr`]. -//! -//! # Protection of reference counts -//! -//! The first idea would be to just use [`AtomicPtr`] with whatever the [`Arc::into_raw`] returns. -//! Then replacing it would be fine (there's no need to update ref counts). The load needs to -//! increment the reference count ‒ one still stays inside and another is returned to the caller. -//! This is done by re-creating the Arc from the raw pointer and then cloning it, throwing one -//! instance away (without destroying it). -//! -//! This approach has a problem. There's a short time between we read the raw pointer and increment -//! the count. If some other thread replaces the stored Arc and throws it away, the ref count could -//! drop to 0, get destroyed and we would be trying to bump ref counts in a ghost, which would be -//! totally broken. -//! -//! To prevent this, we actually use two approaches in a hybrid manner. -//! -//! The first one is based on hazard pointers idea, but slightly modified. There's a global -//! repository of pointers that owe a reference. When someone swaps a pointer, it walks this list -//! and pays all the debts (and takes them out of the repository). -//! -//! For simplicity and performance, storing into the repository is fallible. If storing into the -//! repository fails (because the thread used up all its own slots, or because the pointer got -//! replaced in just the wrong moment and it can't confirm the reservation), unlike the full -//! hazard-pointers approach, we don't retry, but fall back onto secondary strategy. -//! -//! The secondary strategy is similar, but a bit more complex (and therefore slower, that's why it -//! is only a fallback). We first publish an intent to read a pointer (and where we are reading it -//! from). Then we actually do so and publish the debt, like previously. -//! -//! The writer pays the debts as usual. But also, if it sees the intent to read the value, it helps -//! along, reads it, bumps the reference and passes it to the reader. Therefore, if the reader -//! fails to do the protection itself, because it got interrupted by a writer, it finds a -//! ready-made replacement value it can just use and doesn't have to retry. Also, the writer -//! doesn't have to wait for the reader in any way, because it can just solve its problem and move -//! on. -//! -//! # Unsafety -//! -//! All the uses of the unsafe keyword is just to turn the raw pointer back to Arc. It originated -//! from an Arc in the first place, so the only thing to ensure is it is still valid. That means its -//! ref count never dropped to 0. -//! -//! At the beginning, there's ref count of 1 stored in the raw pointer (and maybe some others -//! elsewhere, but we can't rely on these). This 1 stays there for the whole time the pointer is -//! stored there. When the arc is replaced, this 1 is returned to the caller, so we just have to -//! make sure no more readers access it by that time. -//! -//! # Leases and debts -//! -//! Instead of incrementing the reference count, the pointer reference can be owed. In such case, it -//! is recorded into a global storage. As each thread has its own storage (the global storage is -//! composed of multiple thread storages), the readers don't contend. When the pointer is no longer -//! in use, the debt is erased. -//! -//! The writer pays all the existing debts, therefore the reader have the full Arc with ref count at -//! that time. The reader is made aware the debt was paid and decrements the reference count. -//! -//! # Memory orders -//! -//! ## Synchronizing the data pointed to by the pointer. -//! -//! We have AcqRel (well, SeqCst, but that's included) on the swap and Acquire on the loads. In case -//! of the double read around the debt allocation, we do that on the *second*, because of ABA. -//! That's also why that SeqCst on the allocation of debt itself is not enough. -//! the *latest* decrement. By making both the increment and decrement AcqRel, we effectively chain -//! the edges together. -//! -//! # Memory orders around debts -//! -//! The linked list of debt nodes only grows. The shape of the list (existence of nodes) is -//! synchronized through Release on creation and Acquire on load on the head pointer. -//! -//! The debts work similar to locks ‒ Acquire and Release make all the pointer manipulation at the -//! interval where it is written down. However, we use the SeqCst on the allocation of the debt -//! because when we see an empty slot, we need to make sure that it happened after we have -//! overwritten the pointer. -//! -//! In case the writer pays the debt, it sees the new enough data (for the same reasons the stale -//! empties are not seen). The reference count on the Arc is AcqRel and makes sure it is not -//! destroyed too soon. The writer traverses all the slots, therefore they don't need to synchronize -//! with each other. -//! -//! Further details are inside the internal `debt` module. -//! -//! [`RefCnt`]: crate::RefCnt -//! [`Arc`]: std::sync::Arc -//! [`Arc::into_raw`]: std::sync::Arc::into_raw -//! [`Rc`]: std::rc::Rc -//! [`Weak`]: std::sync::Weak -//! [`AtomicPtr`]: std::sync::atomic::AtomicPtr diff --git a/third-party/vendor/arc-swap/src/docs/limitations.rs b/third-party/vendor/arc-swap/src/docs/limitations.rs deleted file mode 100644 index 5d3ca00c..00000000 --- a/third-party/vendor/arc-swap/src/docs/limitations.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Limitations and common pitfalls. -//! -//! # Sized types -//! -//! This currently works only for `Sized` types. Unsized types have „fat pointers“, which are twice -//! as large as the normal ones. The [`AtomicPtr`] doesn't support them. One could use something -//! like `AtomicU128` for them. The catch is this doesn't exist and the difference would make it -//! really hard to implement the debt storage/stripped down hazard pointers. -//! -//! A workaround is to use double indirection: -//! -//! ```rust -//! # use arc_swap::ArcSwap; -//! // This doesn't work: -//! // let data: ArcSwap<[u8]> = ArcSwap::new(Arc::from([1, 2, 3])); -//! -//! // But this does: -//! let data: ArcSwap> = ArcSwap::from_pointee(Box::new([1, 2, 3])); -//! # drop(data); -//! ``` -//! -//! It also may be possible to use `ArcSwap` with the [`triomphe::ThinArc`] (that crate needs -//! enabling a feature flag to cooperate with `ArcSwap`). -//! -//! # Too many [`Guard`]s -//! -//! There's only limited number of "fast" slots for borrowing from [`ArcSwap`] for each single -//! thread (currently 8, but this might change in future versions). If these run out, the algorithm -//! falls back to slower path. -//! -//! If too many [`Guard`]s are kept around, the performance might be poor. These are not intended -//! to be stored in data structures or used across async yield points. -//! -//! [`ArcSwap`]: crate::ArcSwap -//! [`Guard`]: crate::Guard -//! [`AtomicPtr`]: std::sync::atomic::AtomicPtr -//! -//! # No `Clone` implementation -//! -//! Previous version implemented [`Clone`], but it turned out to be very confusing to people, since -//! it created fully independent [`ArcSwap`]. Users expected the instances to be tied to each -//! other, that store in one would change the result of future load of the other. -//! -//! To emulate the original behaviour, one can do something like this: -//! -//! ```rust -//! # use arc_swap::ArcSwap; -//! # let old = ArcSwap::from_pointee(42); -//! let new = ArcSwap::new(old.load_full()); -//! # let _ = new; -//! ``` -//! -//! [`triomphe::ThinArc`]: https://docs.rs/triomphe/latest/triomphe/struct.ThinArc.html diff --git a/third-party/vendor/arc-swap/src/docs/mod.rs b/third-party/vendor/arc-swap/src/docs/mod.rs deleted file mode 100644 index 8ccb27c4..00000000 --- a/third-party/vendor/arc-swap/src/docs/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Additional documentation. -//! -//! Here we have some more general topics that might be good to know that just don't fit to the -//! crate level intro. -//! -//! Also, there were some previous blog posts about the crate which you might find interesting. -//! -//! # Atomic orderings -//! -//! Each operation on the [`ArcSwapAny`] with [`DefaultStrategy`] type callable concurrently (eg. -//! [`load`], but not [`into_inner`]) contains at least one [`SeqCst`] atomic read-write operation, -//! therefore even operations on different instances have a defined global order of operations. -//! -//! # Features -//! -//! The `weak` feature adds the ability to use arc-swap with the [`Weak`] pointer too, -//! through the [`ArcSwapWeak`] type. The needed std support is stabilized in rust version 1.45 (as -//! of now in beta). -//! -//! The `experimental-strategies` enables few more strategies that can be used. Note that these -//! **are not** part of the API stability guarantees and they may be changed, renamed or removed at -//! any time. -//! -//! The `experimental-thread-local` feature can be used to build arc-swap for `no_std` targets, by -//! replacing occurences of [`std::thread_local!`] with the `#[thread_local]` directive. This -//! requires a nightly Rust compiler as it makes use of the experimental -//! [`thread_local`](https://doc.rust-lang.org/unstable-book/language-features/thread-local.html) -//! feature. Using this features, thread-local variables are compiled using LLVM built-ins, which -//! have [several underlying modes of -//! operation](https://doc.rust-lang.org/beta/unstable-book/compiler-flags/tls-model.html). To add -//! support for thread-local variables on a platform that does not have OS or linker support, the -//! easiest way is to use `-Ztls-model=emulated` and to implement `__emutls_get_address` by hand, -//! as in [this -//! example](https://opensource.apple.com/source/clang/clang-800.0.38/src/projects/compiler-rt/lib/builtins/emutls.c.auto.html) -//! from Clang. -//! -//! # Minimal compiler version -//! -//! The `1` versions will compile on all compilers supporting the 2018 edition. Note that this -//! applies only if no additional feature flags are enabled and does not apply to compiling or -//! running tests. -//! -//! [`ArcSwapAny`]: crate::ArcSwapAny -//! [`ArcSwapWeak`]: crate::ArcSwapWeak -//! [`load`]: crate::ArcSwapAny::load -//! [`into_inner`]: crate::ArcSwapAny::into_inner -//! [`DefaultStrategy`]: crate::DefaultStrategy -//! [`SeqCst`]: std::sync::atomic::Ordering::SeqCst -//! [`Weak`]: std::sync::Weak - -pub mod internal; -pub mod limitations; -pub mod patterns; -pub mod performance; diff --git a/third-party/vendor/arc-swap/src/docs/patterns.rs b/third-party/vendor/arc-swap/src/docs/patterns.rs deleted file mode 100644 index b2f91f5c..00000000 --- a/third-party/vendor/arc-swap/src/docs/patterns.rs +++ /dev/null @@ -1,271 +0,0 @@ -//! Common use patterns -//! -//! Here are some common patterns one can use for inspiration. These are mostly covered by examples -//! at the right type in the crate, but this lists them at a single place. -//! -//! # Sharing of configuration data -//! -//! We want to share configuration from some source with rare updates to some high performance -//! worker threads. It can be configuration in its true sense, or a routing table. -//! -//! The idea here is, each new version is a newly allocated in its own [`Arc`]. It is then stored -//! into a *shared* `ArcSwap` instance. -//! -//! Each worker then loads the current version before each work chunk. In case a new version is -//! stored, the worker keeps using the loaded one until it ends the work chunk and, if it's the -//! last one to have the version, deallocates it automatically by dropping the [`Guard`] -//! -//! Note that the configuration needs to be passed through a *single shared* [`ArcSwap`]. That -//! means we need to share that instance and we do so through an [`Arc`] (one could use a global -//! variable instead). -//! -//! Therefore, what we have is `Arc>`. -//! -//! ```rust -//! # use std::sync::Arc; -//! # use std::sync::atomic::{AtomicBool, Ordering}; -//! # use std::thread; -//! # use std::time::Duration; -//! # -//! # use arc_swap::ArcSwap; -//! # struct Work; -//! # impl Work { fn fetch() -> Self { Work } fn perform(&self, _: &Config) {} } -//! # -//! #[derive(Debug, Default)] -//! struct Config { -//! // ... Stuff in here ... -//! } -//! -//! // We wrap the ArcSwap into an Arc, so we can share it between threads. -//! let config = Arc::new(ArcSwap::from_pointee(Config::default())); -//! -//! let terminate = Arc::new(AtomicBool::new(false)); -//! let mut threads = Vec::new(); -//! -//! // The configuration thread -//! threads.push(thread::spawn({ -//! let config = Arc::clone(&config); -//! let terminate = Arc::clone(&terminate); -//! move || { -//! while !terminate.load(Ordering::Relaxed) { -//! thread::sleep(Duration::from_secs(6)); -//! // Actually, load it from somewhere -//! let new_config = Arc::new(Config::default()); -//! config.store(new_config); -//! } -//! } -//! })); -//! -//! // The worker thread -//! for _ in 0..10 { -//! threads.push(thread::spawn({ -//! let config = Arc::clone(&config); -//! let terminate = Arc::clone(&terminate); -//! move || { -//! while !terminate.load(Ordering::Relaxed) { -//! let work = Work::fetch(); -//! let config = config.load(); -//! work.perform(&config); -//! } -//! } -//! })); -//! } -//! -//! // Terminate gracefully -//! terminate.store(true, Ordering::Relaxed); -//! for thread in threads { -//! thread.join().unwrap(); -//! } -//! ``` -//! -//! # Consistent snapshots -//! -//! While one probably wants to get a fresh instance every time a work chunk is available, -//! therefore there would be one [`load`] for each work chunk, it is often also important that the -//! configuration doesn't change in the *middle* of processing of one chunk. Therefore, one -//! commonly wants *exactly* one [`load`] for the work chunk, not *at least* one. If the processing -//! had multiple phases, one would use something like this: -//! -//! ```rust -//! # use std::sync::Arc; -//! # -//! # use arc_swap::ArcSwap; -//! # struct Config; -//! # struct Work; -//! # impl Work { -//! # fn fetch() -> Self { Work } -//! # fn phase_1(&self, _: &Config) {} -//! # fn phase_2(&self, _: &Config) {} -//! # } -//! # let config = Arc::new(ArcSwap::from_pointee(Config)); -//! let work = Work::fetch(); -//! let config = config.load(); -//! work.phase_1(&config); -//! // We keep the same config value here -//! work.phase_2(&config); -//! ``` -//! -//! Over this: -//! -//! ```rust -//! # use std::sync::Arc; -//! # -//! # use arc_swap::ArcSwap; -//! # struct Config; -//! # struct Work; -//! # impl Work { -//! # fn fetch() -> Self { Work } -//! # fn phase_1(&self, _: &Config) {} -//! # fn phase_2(&self, _: &Config) {} -//! # } -//! # let config = Arc::new(ArcSwap::from_pointee(Config)); -//! let work = Work::fetch(); -//! work.phase_1(&config.load()); -//! // WARNING!! This is broken, because in between phase_1 and phase_2, the other thread could -//! // have replaced the config. Then each phase would be performed with a different one and that -//! // could lead to surprises. -//! work.phase_2(&config.load()); -//! ``` -//! -//! # Caching of the configuration -//! -//! Let's say that the work chunks are really small, but there's *a lot* of them to work on. Maybe -//! we are routing packets and the configuration is the routing table that can sometimes change, -//! but mostly doesn't. -//! -//! There's an overhead to [`load`]. If the work chunks are small enough, that could be measurable. -//! We can reach for [`Cache`]. It makes loads much faster (in the order of accessing local -//! variables) in case nothing has changed. It has two costs, it makes the load slightly slower in -//! case the thing *did* change (which is rare) and if the worker is inactive, it holds the old -//! cached value alive. -//! -//! This is OK for our use case, because the routing table is usually small enough so some stale -//! instances taking a bit of memory isn't an issue. -//! -//! The part that takes care of updates stays the same as above. -//! -//! ```rust -//! # use std::sync::Arc; -//! # use std::thread; -//! # use std::sync::atomic::{AtomicBool, Ordering}; -//! # use arc_swap::{ArcSwap, Cache}; -//! # struct Packet; impl Packet { fn receive() -> Self { Packet } } -//! -//! #[derive(Debug, Default)] -//! struct RoutingTable { -//! // ... Stuff in here ... -//! } -//! -//! impl RoutingTable { -//! fn route(&self, _: Packet) { -//! // ... Interesting things are done here ... -//! } -//! } -//! -//! let routing_table = Arc::new(ArcSwap::from_pointee(RoutingTable::default())); -//! -//! let terminate = Arc::new(AtomicBool::new(false)); -//! let mut threads = Vec::new(); -//! -//! for _ in 0..10 { -//! let t = thread::spawn({ -//! let routing_table = Arc::clone(&routing_table); -//! let terminate = Arc::clone(&terminate); -//! move || { -//! let mut routing_table = Cache::new(routing_table); -//! while !terminate.load(Ordering::Relaxed) { -//! let packet = Packet::receive(); -//! // This load is cheaper, because we cache in the private Cache thing. -//! // But if the above receive takes a long time, the Cache will keep the stale -//! // value alive until this time (when it will get replaced by up to date value). -//! let current = routing_table.load(); -//! current.route(packet); -//! } -//! } -//! }); -//! threads.push(t); -//! } -//! -//! // Shut down properly -//! terminate.store(true, Ordering::Relaxed); -//! for thread in threads { -//! thread.join().unwrap(); -//! } -//! ``` -//! -//! # Projecting into configuration field -//! -//! We have a larger application, composed of multiple components. Each component has its own -//! `ComponentConfig` structure. Then, the whole application has a `Config` structure that contains -//! a component config for each component: -//! -//! ```rust -//! # struct ComponentConfig; -//! -//! struct Config { -//! component: ComponentConfig, -//! // ... Some other components and things ... -//! } -//! # let c = Config { component: ComponentConfig }; -//! # let _ = c.component; -//! ``` -//! -//! We would like to use [`ArcSwap`] to push updates to the components. But for various reasons, -//! it's not a good idea to put the whole `ArcSwap` to each component, eg: -//! -//! * That would make each component depend on the top level config, which feels reversed. -//! * It doesn't allow reusing the same component in multiple applications, as these would have -//! different `Config` structures. -//! * One needs to build the whole `Config` for tests. -//! * There's a risk of entanglement, that the component would start looking at configuration of -//! different parts of code, which would be hard to debug. -//! -//! We also could have a separate `ArcSwap` for each component, but that also -//! doesn't feel right, as we would have to push updates to multiple places and they could be -//! inconsistent for a while and we would have to decompose the `Config` structure into the parts, -//! because we need our things in [`Arc`]s to be put into [`ArcSwap`]. -//! -//! This is where the [`Access`] trait comes into play. The trait abstracts over things that can -//! give access to up to date version of specific T. That can be a [`Constant`] (which is useful -//! mostly for the tests, where one doesn't care about the updating), it can be an -//! [`ArcSwap`][`ArcSwap`] itself, but it also can be an [`ArcSwap`] paired with a closure to -//! project into the specific field. The [`DynAccess`] is similar, but allows type erasure. That's -//! more convenient, but a little bit slower. -//! -//! ```rust -//! # use std::sync::Arc; -//! # use arc_swap::ArcSwap; -//! # use arc_swap::access::{DynAccess, Map}; -//! -//! #[derive(Debug, Default)] -//! struct ComponentConfig; -//! -//! struct Component { -//! config: Box>, -//! } -//! -//! #[derive(Debug, Default)] -//! struct Config { -//! component: ComponentConfig, -//! } -//! -//! let config = Arc::new(ArcSwap::from_pointee(Config::default())); -//! -//! let component = Component { -//! config: Box::new(Map::new(Arc::clone(&config), |config: &Config| &config.component)), -//! }; -//! # let _ = component.config; -//! ``` -//! -//! One would use `Box::new(Constant(ComponentConfig))` in unittests instead as the `config` field. -//! -//! The [`Cache`] has its own [`Access`][crate::cache::Access] trait for similar purposes. -//! -//! [`Arc`]: std::sync::Arc -//! [`Guard`]: crate::Guard -//! [`load`]: crate::ArcSwapAny::load -//! [`ArcSwap`]: crate::ArcSwap -//! [`Cache`]: crate::cache::Cache -//! [`Access`]: crate::access::Access -//! [`DynAccess`]: crate::access::DynAccess -//! [`Constant`]: crate::access::Constant diff --git a/third-party/vendor/arc-swap/src/docs/performance.rs b/third-party/vendor/arc-swap/src/docs/performance.rs deleted file mode 100644 index 6358c874..00000000 --- a/third-party/vendor/arc-swap/src/docs/performance.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Performance characteristics. -//! -//! There are several performance advantages of [`ArcSwap`] over [`RwLock`]. -//! -//! ## Lock-free readers -//! -//! All the read operations are always [lock-free]. Most of the time, they are actually -//! [wait-free]. They are [lock-free] from time to time, with at least `usize::MAX / 4` accesses -//! that are [wait-free] in between. -//! -//! Writers are [lock-free]. -//! -//! Whenever the documentation talks about *contention* in the context of [`ArcSwap`], it talks -//! about contention on the CPU level ‒ multiple cores having to deal with accessing the same cache -//! line. This slows things down (compared to each one accessing its own cache line), but an -//! eventual progress is still guaranteed and the cost is significantly lower than parking threads -//! as with mutex-style contention. -//! -//! ## Speeds -//! -//! The base line speed of read operations is similar to using an *uncontended* [`Mutex`]. -//! However, [`load`] suffers no contention from any other read operations and only slight -//! ones during updates. The [`load_full`] operation is additionally contended only on -//! the reference count of the [`Arc`] inside ‒ so, in general, while [`Mutex`] rapidly -//! loses its performance when being in active use by multiple threads at once and -//! [`RwLock`] is slow to start with, [`ArcSwap`] mostly keeps its performance even when read by -//! many threads in parallel. -//! -//! Write operations are considered expensive. A write operation is more expensive than access to -//! an *uncontended* [`Mutex`] and on some architectures even slower than uncontended -//! [`RwLock`]. However, it is faster than either under contention. -//! -//! There are some (very unscientific) [benchmarks] within the source code of the library, and the -//! [`DefaultStrategy`][crate::DefaultStrategy] has some numbers measured on my computer. -//! -//! The exact numbers are highly dependant on the machine used (both absolute numbers and relative -//! between different data structures). Not only architectures have a huge impact (eg. x86 vs ARM), -//! but even AMD vs. Intel or two different Intel processors. Therefore, if what matters is more -//! the speed than the wait-free guarantees, you're advised to do your own measurements. -//! -//! Further speed improvements may be gained by the use of the [`Cache`]. -//! -//! ## Consistency -//! -//! The combination of [wait-free] guarantees of readers and no contention between concurrent -//! [`load`]s provides *consistent* performance characteristics of the synchronization mechanism. -//! This might be important for soft-realtime applications (the CPU-level contention caused by a -//! recent update/write operation might be problematic for some hard-realtime cases, though). -//! -//! ## Choosing the right reading operation -//! -//! There are several load operations available. While the general go-to one should be -//! [`load`], there may be situations in which the others are a better match. -//! -//! The [`load`] usually only borrows the instance from the shared [`ArcSwap`]. This makes -//! it faster, because different threads don't contend on the reference count. There are two -//! situations when this borrow isn't possible. If the content gets changed, all existing -//! [`Guard`]s are promoted to contain an owned instance. The promotion is done by the -//! writer, but the readers still need to decrement the reference counts of the old instance when -//! they no longer use it, contending on the count. -//! -//! The other situation derives from internal implementation. The number of borrows each thread can -//! have at each time (across all [`Guard`]s) is limited. If this limit is exceeded, an owned -//! instance is created instead. -//! -//! Therefore, if you intend to hold onto the loaded value for extended time span, you may prefer -//! [`load_full`]. It loads the pointer instance ([`Arc`]) without borrowing, which is -//! slower (because of the possible contention on the reference count), but doesn't consume one of -//! the borrow slots, which will make it more likely for following [`load`]s to have a slot -//! available. Similarly, if some API needs an owned `Arc`, [`load_full`] is more convenient and -//! potentially faster then first [`load`]ing and then cloning that [`Arc`]. -//! -//! Additionally, it is possible to use a [`Cache`] to get further speed improvement at the -//! cost of less comfortable API and possibly keeping the older values alive for longer than -//! necessary. -//! -//! [`ArcSwap`]: crate::ArcSwap -//! [`Cache`]: crate::cache::Cache -//! [`Guard`]: crate::Guard -//! [`load`]: crate::ArcSwapAny::load -//! [`load_full`]: crate::ArcSwapAny::load_full -//! [`Arc`]: std::sync::Arc -//! [`Mutex`]: std::sync::Mutex -//! [`RwLock`]: std::sync::RwLock -//! [benchmarks]: https://github.com/vorner/arc-swap/tree/master/benchmarks -//! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom -//! [wait-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom diff --git a/third-party/vendor/arc-swap/src/lib.rs b/third-party/vendor/arc-swap/src/lib.rs deleted file mode 100644 index 6995abd7..00000000 --- a/third-party/vendor/arc-swap/src/lib.rs +++ /dev/null @@ -1,1317 +0,0 @@ -#![doc(test(attr(deny(warnings))))] -#![warn(missing_docs)] -#![cfg_attr(docsrs, feature(doc_cfg))] -#![allow(deprecated)] -#![cfg_attr(feature = "experimental-thread-local", no_std)] -#![cfg_attr(feature = "experimental-thread-local", feature(thread_local))] - -//! Making [`Arc`][Arc] itself atomic -//! -//! The [`ArcSwap`] type is a container for an `Arc` that can be changed atomically. Semantically, -//! it is similar to something like `Atomic>` (if there was such a thing) or -//! `RwLock>` (but without the need for the locking). It is optimized for read-mostly -//! scenarios, with consistent performance characteristics. -//! -//! # Motivation -//! -//! There are many situations in which one might want to have some data structure that is often -//! read and seldom updated. Some examples might be a configuration of a service, routing tables, -//! snapshot of some data that is renewed every few minutes, etc. -//! -//! In all these cases one needs: -//! * Being able to read the current value of the data structure, fast, often and concurrently from -//! many threads. -//! * Using the same version of the data structure over longer period of time ‒ a query should be -//! answered by a consistent version of data, a packet should be routed either by an old or by a -//! new version of the routing table but not by a combination, etc. -//! * Perform an update without disrupting the processing. -//! -//! The first idea would be to use [`RwLock`][RwLock] and keep a read-lock for the whole time of -//! processing. Update would, however, pause all processing until done. -//! -//! Better option would be to have [`RwLock>`][RwLock]. Then one would lock, clone the [Arc] -//! and unlock. This suffers from CPU-level contention (on the lock and on the reference count of -//! the [Arc]) which makes it relatively slow. Depending on the implementation, an update may be -//! blocked for arbitrary long time by a steady inflow of readers. -//! -//! ```rust -//! # use std::sync::{Arc, RwLock}; -//! # use once_cell::sync::Lazy; -//! # struct RoutingTable; struct Packet; impl RoutingTable { fn route(&self, _: Packet) {} } -//! static ROUTING_TABLE: Lazy>> = Lazy::new(|| { -//! RwLock::new(Arc::new(RoutingTable)) -//! }); -//! -//! fn process_packet(packet: Packet) { -//! let table = Arc::clone(&ROUTING_TABLE.read().unwrap()); -//! table.route(packet); -//! } -//! # fn main() { process_packet(Packet); } -//! ``` -//! -//! The [ArcSwap] can be used instead, which solves the above problems and has better performance -//! characteristics than the [RwLock], both in contended and non-contended scenarios. -//! -//! ```rust -//! # use arc_swap::ArcSwap; -//! # use once_cell::sync::Lazy; -//! # struct RoutingTable; struct Packet; impl RoutingTable { fn route(&self, _: Packet) {} } -//! static ROUTING_TABLE: Lazy> = Lazy::new(|| { -//! ArcSwap::from_pointee(RoutingTable) -//! }); -//! -//! fn process_packet(packet: Packet) { -//! let table = ROUTING_TABLE.load(); -//! table.route(packet); -//! } -//! # fn main() { process_packet(Packet); } -//! ``` -//! -//! # Crate contents -//! -//! At the heart of the crate there are [`ArcSwap`] and [`ArcSwapOption`] types, containers for an -//! [`Arc`] and [`Option`][Option]. -//! -//! Technically, these are type aliases for partial instantiations of the [`ArcSwapAny`] type. The -//! [`ArcSwapAny`] is more flexible and allows tweaking of many things (can store other things than -//! [`Arc`]s, can configure the locking [`Strategy`]). For details about the tweaking, see the -//! documentation of the [`strategy`] module and the [`RefCnt`] trait. -//! -//! The [`cache`] module provides means for speeding up read access of the contained data at the -//! cost of delayed reclamation. -//! -//! The [`access`] module can be used to do projections into the contained data to separate parts -//! of application from each other (eg. giving a component access to only its own part of -//! configuration while still having it reloaded as a whole). -//! -//! # Before using -//! -//! The data structure is a bit niche. Before using, please check the -//! [limitations and common pitfalls][docs::limitations] and the [performance -//! characteristics][docs::performance], including choosing the right [read -//! operation][docs::performance#read-operations]. -//! -//! You can also get an inspiration about what's possible in the [common patterns][docs::patterns] -//! section. -//! -//! # Examples -//! -//! ```rust -//! use std::sync::Arc; -//! -//! use arc_swap::ArcSwap; -//! use crossbeam_utils::thread; -//! -//! let config = ArcSwap::from(Arc::new(String::default())); -//! thread::scope(|scope| { -//! scope.spawn(|_| { -//! let new_conf = Arc::new("New configuration".to_owned()); -//! config.store(new_conf); -//! }); -//! for _ in 0..10 { -//! scope.spawn(|_| { -//! loop { -//! let cfg = config.load(); -//! if !cfg.is_empty() { -//! assert_eq!(**cfg, "New configuration"); -//! return; -//! } -//! } -//! }); -//! } -//! }).unwrap(); -//! ``` -//! -//! [RwLock]: https://doc.rust-lang.org/std/sync/struct.RwLock.html - -#[allow(unused_imports)] -#[macro_use] -extern crate alloc; - -pub mod access; -mod as_raw; -pub mod cache; -mod compile_fail_tests; -mod debt; -pub mod docs; -mod ref_cnt; -#[cfg(feature = "serde")] -mod serde; -pub mod strategy; -#[cfg(feature = "weak")] -mod weak; - -use core::borrow::Borrow; -use core::fmt::{Debug, Display, Formatter, Result as FmtResult}; -use core::marker::PhantomData; -use core::mem; -use core::ops::Deref; -use core::ptr; -use core::sync::atomic::{AtomicPtr, Ordering}; - -use alloc::sync::Arc; - -use crate::access::{Access, Map}; -pub use crate::as_raw::AsRaw; -pub use crate::cache::Cache; -pub use crate::ref_cnt::RefCnt; -use crate::strategy::hybrid::{DefaultConfig, HybridStrategy}; -use crate::strategy::sealed::Protected; -use crate::strategy::{CaS, Strategy}; -pub use crate::strategy::{DefaultStrategy, IndependentStrategy}; - -/// A temporary storage of the pointer. -/// -/// This guard object is returned from most loading methods (with the notable exception of -/// [`load_full`](struct.ArcSwapAny.html#method.load_full)). It dereferences to the smart pointer -/// loaded, so most operations are to be done using that. -pub struct Guard = DefaultStrategy> { - inner: S::Protected, -} - -impl> Guard { - /// Converts it into the held value. - /// - /// This, on occasion, may be a tiny bit faster than cloning the Arc or whatever is being held - /// inside. - // Associated function on purpose, because of deref - #[allow(clippy::wrong_self_convention)] - #[inline] - pub fn into_inner(lease: Self) -> T { - lease.inner.into_inner() - } - - /// Create a guard for a given value `inner`. - /// - /// This can be useful on occasion to pass a specific object to code that expects or - /// wants to store a Guard. - /// - /// # Example - /// - /// ```rust - /// # use arc_swap::{ArcSwap, DefaultStrategy, Guard}; - /// # use std::sync::Arc; - /// # let p = ArcSwap::from_pointee(42); - /// // Create two guards pointing to the same object - /// let g1 = p.load(); - /// let g2 = Guard::<_, DefaultStrategy>::from_inner(Arc::clone(&*g1)); - /// # drop(g2); - /// ``` - pub fn from_inner(inner: T) -> Self { - Guard { - inner: S::Protected::from_inner(inner), - } - } -} - -impl> Deref for Guard { - type Target = T; - #[inline] - fn deref(&self) -> &T { - self.inner.borrow() - } -} - -impl> From for Guard { - fn from(inner: T) -> Self { - Self::from_inner(inner) - } -} - -impl> Default for Guard { - fn default() -> Self { - Self::from(T::default()) - } -} - -impl> Debug for Guard { - fn fmt(&self, formatter: &mut Formatter) -> FmtResult { - self.deref().fmt(formatter) - } -} - -impl> Display for Guard { - fn fmt(&self, formatter: &mut Formatter) -> FmtResult { - self.deref().fmt(formatter) - } -} - -/// Comparison of two pointer-like things. -// A and B are likely to *be* references, or thin wrappers around that. Calling that with extra -// reference is just annoying. -#[allow(clippy::needless_pass_by_value)] -fn ptr_eq(a: A, b: B) -> bool -where - A: AsRaw, - B: AsRaw, -{ - let a = a.as_raw(); - let b = b.as_raw(); - ptr::eq(a, b) -} - -/// An atomic storage for a reference counted smart pointer like [`Arc`] or `Option`. -/// -/// This is a storage where a smart pointer may live. It can be read and written atomically from -/// several threads, but doesn't act like a pointer itself. -/// -/// One can be created [`from`] an [`Arc`]. To get the pointer back, use the -/// [`load`](#method.load). -/// -/// # Note -/// -/// This is the common generic implementation. This allows sharing the same code for storing -/// both `Arc` and `Option` (and possibly other similar types). -/// -/// In your code, you most probably want to interact with it through the -/// [`ArcSwap`](type.ArcSwap.html) and [`ArcSwapOption`](type.ArcSwapOption.html) aliases. However, -/// the methods they share are described here and are applicable to both of them. That's why the -/// examples here use `ArcSwap` ‒ but they could as well be written with `ArcSwapOption` or -/// `ArcSwapAny`. -/// -/// # Type parameters -/// -/// * `T`: The smart pointer to be kept inside. This crate provides implementation for `Arc<_>` and -/// `Option>` (`Rc` too, but that one is not practically useful). But third party could -/// provide implementations of the [`RefCnt`] trait and plug in others. -/// * `S`: Chooses the [strategy] used to protect the data inside. They come with various -/// performance trade offs, the default [`DefaultStrategy`] is good rule of thumb for most use -/// cases. -/// -/// # Examples -/// -/// ```rust -/// # use std::sync::Arc; -/// # use arc_swap::ArcSwap; -/// let arc = Arc::new(42); -/// let arc_swap = ArcSwap::from(arc); -/// assert_eq!(42, **arc_swap.load()); -/// // It can be read multiple times -/// assert_eq!(42, **arc_swap.load()); -/// -/// // Put a new one in there -/// let new_arc = Arc::new(0); -/// assert_eq!(42, *arc_swap.swap(new_arc)); -/// assert_eq!(0, **arc_swap.load()); -/// ``` -/// -/// # Known bugs -/// -/// Currently, things like `ArcSwapAny>>>` (notice the double Option) don't -/// work properly. A proper solution is being looked into -/// ([#81](https://github.com/vorner/arc-swap/issues)). -/// -/// [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html -/// [`from`]: https://doc.rust-lang.org/nightly/std/convert/trait.From.html#tymethod.from -/// [`RefCnt`]: trait.RefCnt.html -pub struct ArcSwapAny = DefaultStrategy> { - // Notes: AtomicPtr needs Sized - /// The actual pointer, extracted from the Arc. - ptr: AtomicPtr, - - /// We are basically an Arc in disguise. Inherit parameters from Arc by pretending to contain - /// it. - _phantom_arc: PhantomData, - - /// Strategy to protect the data. - strategy: S, -} - -impl> From for ArcSwapAny { - fn from(val: T) -> Self { - Self::with_strategy(val, S::default()) - } -} - -impl> Drop for ArcSwapAny { - fn drop(&mut self) { - let ptr = *self.ptr.get_mut(); - unsafe { - // To pay any possible debts - self.strategy.wait_for_readers(ptr, &self.ptr); - // We are getting rid of the one stored ref count - T::dec(ptr); - } - } -} - -impl> Debug for ArcSwapAny -where - T: Debug + RefCnt, -{ - fn fmt(&self, formatter: &mut Formatter) -> FmtResult { - formatter - .debug_tuple("ArcSwapAny") - .field(&self.load()) - .finish() - } -} - -impl> Display for ArcSwapAny -where - T: Display + RefCnt, -{ - fn fmt(&self, formatter: &mut Formatter) -> FmtResult { - self.load().fmt(formatter) - } -} - -impl> Default for ArcSwapAny { - fn default() -> Self { - Self::new(T::default()) - } -} - -impl> ArcSwapAny { - /// Constructs a new storage. - pub fn new(val: T) -> Self - where - S: Default, - { - Self::from(val) - } - - /// Constructs a new storage while customizing the protection strategy. - pub fn with_strategy(val: T, strategy: S) -> Self { - // The AtomicPtr requires *mut in its interface. We are more like *const, so we cast it. - // However, we always go back to *const right away when we get the pointer on the other - // side, so it should be fine. - let ptr = T::into_ptr(val); - Self { - ptr: AtomicPtr::new(ptr), - _phantom_arc: PhantomData, - strategy, - } - } - - /// Extracts the value inside. - pub fn into_inner(mut self) -> T { - let ptr = *self.ptr.get_mut(); - // To pay all the debts - unsafe { self.strategy.wait_for_readers(ptr, &self.ptr) }; - mem::forget(self); - unsafe { T::from_ptr(ptr) } - } - - /// Loads the value. - /// - /// This makes another copy of the held pointer and returns it, atomically (it is - /// safe even when other thread stores into the same instance at the same time). - /// - /// The method is lock-free and wait-free, but usually more expensive than - /// [`load`](#method.load). - pub fn load_full(&self) -> T { - Guard::into_inner(self.load()) - } - - /// Provides a temporary borrow of the object inside. - /// - /// This returns a proxy object allowing access to the thing held inside. However, there's - /// only limited amount of possible cheap proxies in existence for each thread ‒ if more are - /// created, it falls back to equivalent of [`load_full`](#method.load_full) internally. - /// - /// This is therefore a good choice to use for eg. searching a data structure or juggling the - /// pointers around a bit, but not as something to store in larger amounts. The rule of thumb - /// is this is suited for local variables on stack, but not in long-living data structures. - /// - /// # Consistency - /// - /// In case multiple related operations are to be done on the loaded value, it is generally - /// recommended to call `load` just once and keep the result over calling it multiple times. - /// First, keeping it is usually faster. But more importantly, the value can change between the - /// calls to load, returning different objects, which could lead to logical inconsistency. - /// Keeping the result makes sure the same object is used. - /// - /// ```rust - /// # use arc_swap::ArcSwap; - /// struct Point { - /// x: usize, - /// y: usize, - /// } - /// - /// fn print_broken(p: &ArcSwap) { - /// // This is broken, because the x and y may come from different points, - /// // combining into an invalid point that never existed. - /// println!("X: {}", p.load().x); - /// // If someone changes the content now, between these two loads, we - /// // have a problem - /// println!("Y: {}", p.load().y); - /// } - /// - /// fn print_correct(p: &ArcSwap) { - /// // Here we take a snapshot of one specific point so both x and y come - /// // from the same one. - /// let point = p.load(); - /// println!("X: {}", point.x); - /// println!("Y: {}", point.y); - /// } - /// # let p = ArcSwap::from_pointee(Point { x: 10, y: 20 }); - /// # print_correct(&p); - /// # print_broken(&p); - /// ``` - #[inline] - pub fn load(&self) -> Guard { - let protected = unsafe { self.strategy.load(&self.ptr) }; - Guard { inner: protected } - } - - /// Replaces the value inside this instance. - /// - /// Further loads will yield the new value. Uses [`swap`](#method.swap) internally. - pub fn store(&self, val: T) { - drop(self.swap(val)); - } - - /// Exchanges the value inside this instance. - pub fn swap(&self, new: T) -> T { - let new = T::into_ptr(new); - // AcqRel needed to publish the target of the new pointer and get the target of the old - // one. - // - // SeqCst to synchronize the time lines with the group counters. - let old = self.ptr.swap(new, Ordering::SeqCst); - unsafe { - self.strategy.wait_for_readers(old, &self.ptr); - T::from_ptr(old) - } - } - - /// Swaps the stored Arc if it equals to `current`. - /// - /// If the current value of the `ArcSwapAny` equals to `current`, the `new` is stored inside. - /// If not, nothing happens. - /// - /// The previous value (no matter if the swap happened or not) is returned. Therefore, if the - /// returned value is equal to `current`, the swap happened. You want to do a pointer-based - /// comparison to determine it. - /// - /// In other words, if the caller „guesses“ the value of current correctly, it acts like - /// [`swap`](#method.swap), otherwise it acts like [`load_full`](#method.load_full) (including - /// the limitations). - /// - /// The `current` can be specified as `&Arc`, [`Guard`](struct.Guard.html), - /// [`&Guards`](struct.Guards.html) or as a raw pointer (but _not_ owned `Arc`). See the - /// [`AsRaw`] trait. - pub fn compare_and_swap(&self, current: C, new: T) -> Guard - where - C: AsRaw, - S: CaS, - { - let protected = unsafe { self.strategy.compare_and_swap(&self.ptr, current, new) }; - Guard { inner: protected } - } - - /// Read-Copy-Update of the pointer inside. - /// - /// This is useful in read-heavy situations with several threads that sometimes update the data - /// pointed to. The readers can just repeatedly use [`load`](#method.load) without any locking. - /// The writer uses this method to perform the update. - /// - /// In case there's only one thread that does updates or in case the next version is - /// independent of the previous one, simple [`swap`](#method.swap) or [`store`](#method.store) - /// is enough. Otherwise, it may be needed to retry the update operation if some other thread - /// made an update in between. This is what this method does. - /// - /// # Examples - /// - /// This will *not* work as expected, because between loading and storing, some other thread - /// might have updated the value. - /// - /// ```rust - /// # use std::sync::Arc; - /// # - /// # use arc_swap::ArcSwap; - /// # use crossbeam_utils::thread; - /// # - /// let cnt = ArcSwap::from_pointee(0); - /// thread::scope(|scope| { - /// for _ in 0..10 { - /// scope.spawn(|_| { - /// let inner = cnt.load_full(); - /// // Another thread might have stored some other number than what we have - /// // between the load and store. - /// cnt.store(Arc::new(*inner + 1)); - /// }); - /// } - /// }).unwrap(); - /// // This will likely fail: - /// // assert_eq!(10, *cnt.load_full()); - /// ``` - /// - /// This will, but it can call the closure multiple times to retry: - /// - /// ```rust - /// # use arc_swap::ArcSwap; - /// # use crossbeam_utils::thread; - /// # - /// let cnt = ArcSwap::from_pointee(0); - /// thread::scope(|scope| { - /// for _ in 0..10 { - /// scope.spawn(|_| cnt.rcu(|inner| **inner + 1)); - /// } - /// }).unwrap(); - /// assert_eq!(10, *cnt.load_full()); - /// ``` - /// - /// Due to the retries, you might want to perform all the expensive operations *before* the - /// rcu. As an example, if there's a cache of some computations as a map, and the map is cheap - /// to clone but the computations are not, you could do something like this: - /// - /// ```rust - /// # use std::collections::HashMap; - /// # - /// # use arc_swap::ArcSwap; - /// # use once_cell::sync::Lazy; - /// # - /// fn expensive_computation(x: usize) -> usize { - /// x * 2 // Let's pretend multiplication is *really expensive expensive* - /// } - /// - /// type Cache = HashMap; - /// - /// static CACHE: Lazy> = Lazy::new(|| ArcSwap::default()); - /// - /// fn cached_computation(x: usize) -> usize { - /// let cache = CACHE.load(); - /// if let Some(result) = cache.get(&x) { - /// return *result; - /// } - /// // Not in cache. Compute and store. - /// // The expensive computation goes outside, so it is not retried. - /// let result = expensive_computation(x); - /// CACHE.rcu(|cache| { - /// // The cheaper clone of the cache can be retried if need be. - /// let mut cache = HashMap::clone(&cache); - /// cache.insert(x, result); - /// cache - /// }); - /// result - /// } - /// - /// assert_eq!(42, cached_computation(21)); - /// assert_eq!(42, cached_computation(21)); - /// ``` - /// - /// # The cost of cloning - /// - /// Depending on the size of cache above, the cloning might not be as cheap. You can however - /// use persistent data structures ‒ each modification creates a new data structure, but it - /// shares most of the data with the old one (which is usually accomplished by using `Arc`s - /// inside to share the unchanged values). Something like - /// [`rpds`](https://crates.io/crates/rpds) or [`im`](https://crates.io/crates/im) might do - /// what you need. - pub fn rcu(&self, mut f: F) -> T - where - F: FnMut(&T) -> R, - R: Into, - S: CaS, - { - let mut cur = self.load(); - loop { - let new = f(&cur).into(); - let prev = self.compare_and_swap(&*cur, new); - let swapped = ptr_eq(&*cur, &*prev); - if swapped { - return Guard::into_inner(prev); - } else { - cur = prev; - } - } - } - - /// Provides an access to an up to date projection of the carried data. - /// - /// # Motivation - /// - /// Sometimes, an application consists of components. Each component has its own configuration - /// structure. The whole configuration contains all the smaller config parts. - /// - /// For the sake of separation and abstraction, it is not desirable to pass the whole - /// configuration to each of the components. This allows the component to take only access to - /// its own part. - /// - /// # Lifetimes & flexibility - /// - /// This method is not the most flexible way, as the returned type borrows into the `ArcSwap`. - /// To provide access into eg. `Arc>`, you can create the [`Map`] type directly. See - /// the [`access`] module. - /// - /// # Performance - /// - /// As the provided function is called on each load from the shared storage, it should - /// generally be cheap. It is expected this will usually be just referencing of a field inside - /// the structure. - /// - /// # Examples - /// - /// ```rust - /// use std::sync::Arc; - /// - /// use arc_swap::ArcSwap; - /// use arc_swap::access::Access; - /// - /// struct Cfg { - /// value: usize, - /// } - /// - /// fn print_many_times>(value: V) { - /// for _ in 0..25 { - /// let value = value.load(); - /// println!("{}", *value); - /// } - /// } - /// - /// let shared = ArcSwap::from_pointee(Cfg { value: 0 }); - /// let mapped = shared.map(|c: &Cfg| &c.value); - /// crossbeam_utils::thread::scope(|s| { - /// // Will print some zeroes and some twos - /// s.spawn(|_| print_many_times(mapped)); - /// s.spawn(|_| shared.store(Arc::new(Cfg { value: 2 }))); - /// }).expect("Something panicked in a thread"); - /// ``` - pub fn map(&self, f: F) -> Map<&Self, I, F> - where - F: Fn(&I) -> &R + Clone, - Self: Access, - { - Map::new(self, f) - } -} - -/// An atomic storage for `Arc`. -/// -/// This is a type alias only. Most of its methods are described on -/// [`ArcSwapAny`](struct.ArcSwapAny.html). -pub type ArcSwap = ArcSwapAny>; - -impl>> ArcSwapAny, S> { - /// A convenience constructor directly from the pointed-to value. - /// - /// Direct equivalent for `ArcSwap::new(Arc::new(val))`. - pub fn from_pointee(val: T) -> Self - where - S: Default, - { - Self::from(Arc::new(val)) - } -} - -/// An atomic storage for `Option`. -/// -/// This is very similar to [`ArcSwap`](type.ArcSwap.html), but allows storing NULL values, which -/// is useful in some situations. -/// -/// This is a type alias only. Most of the methods are described on -/// [`ArcSwapAny`](struct.ArcSwapAny.html). Even though the examples there often use `ArcSwap`, -/// they are applicable to `ArcSwapOption` with appropriate changes. -/// -/// # Examples -/// -/// ``` -/// use std::sync::Arc; -/// use arc_swap::ArcSwapOption; -/// -/// let shared = ArcSwapOption::from(None); -/// assert!(shared.load_full().is_none()); -/// assert!(shared.swap(Some(Arc::new(42))).is_none()); -/// assert_eq!(42, **shared.load_full().as_ref().unwrap()); -/// ``` -pub type ArcSwapOption = ArcSwapAny>>; - -impl>>> ArcSwapAny>, S> { - /// A convenience constructor directly from a pointed-to value. - /// - /// This just allocates the `Arc` under the hood. - /// - /// # Examples - /// - /// ```rust - /// use arc_swap::ArcSwapOption; - /// - /// let empty: ArcSwapOption = ArcSwapOption::from_pointee(None); - /// assert!(empty.load().is_none()); - /// let non_empty: ArcSwapOption = ArcSwapOption::from_pointee(42); - /// assert_eq!(42, **non_empty.load().as_ref().unwrap()); - /// ``` - pub fn from_pointee>>(val: V) -> Self - where - S: Default, - { - Self::new(val.into().map(Arc::new)) - } - - /// A convenience constructor for an empty value. - /// - /// This is equivalent to `ArcSwapOption::new(None)`. - pub fn empty() -> Self - where - S: Default, - { - Self::new(None) - } -} - -impl ArcSwapOption { - /// A const-fn equivalent of [empty]. - /// - /// Just like [empty], this creates an `None`-holding `ArcSwapOption`. The [empty] is, however, - /// more general ‒ this is available only for the default strategy, while [empty] is for any - /// [Default]-constructible strategy (current or future one). - /// - /// [empty]: ArcSwapAny::empty - /// - /// # Examples - /// - /// ```rust - /// # use std::sync::Arc; - /// # use arc_swap::ArcSwapOption; - /// static GLOBAL_DATA: ArcSwapOption = ArcSwapOption::const_empty(); - /// - /// assert!(GLOBAL_DATA.load().is_none()); - /// GLOBAL_DATA.store(Some(Arc::new(42))); - /// assert_eq!(42, **GLOBAL_DATA.load().as_ref().unwrap()); - /// ``` - pub const fn const_empty() -> Self { - Self { - ptr: AtomicPtr::new(ptr::null_mut()), - _phantom_arc: PhantomData, - strategy: HybridStrategy { - _config: DefaultConfig, - }, - } - } -} - -/// An atomic storage that doesn't share the internal generation locks with others. -/// -/// This makes it bigger and it also might suffer contention (on the HW level) if used from many -/// threads at once. On the other hand, it can't block writes in other instances. -/// -/// See the [`IndependentStrategy`] for further details. -// Being phased out. Will deprecate once we verify in production that the new strategy works fine. -#[doc(hidden)] -pub type IndependentArcSwap = ArcSwapAny, IndependentStrategy>; - -/// Arc swap for the [Weak] pointer. -/// -/// This is similar to [ArcSwap], but it doesn't store [Arc], it stores [Weak]. It doesn't keep the -/// data alive when pointed to. -/// -/// This is a type alias only. Most of the methods are described on the -/// [`ArcSwapAny`](struct.ArcSwapAny.html). -/// -/// Needs the `weak` feature turned on. -/// -/// [Weak]: std::sync::Weak -#[cfg(feature = "weak")] -pub type ArcSwapWeak = ArcSwapAny>; - -macro_rules! t { - ($name: ident, $strategy: ty) => { - #[cfg(test)] - mod $name { - use alloc::borrow::ToOwned; - use alloc::string::String; - use alloc::vec::Vec; - use core::sync::atomic::{self, AtomicUsize}; - - use adaptive_barrier::{Barrier, PanicMode}; - use crossbeam_utils::thread; - - use super::*; - - const ITERATIONS: usize = 10; - - #[allow(deprecated)] // We use "deprecated" testing strategies in here. - type As = ArcSwapAny, $strategy>; - #[allow(deprecated)] // We use "deprecated" testing strategies in here. - type Aso = ArcSwapAny>, $strategy>; - - /// Similar to the one in doc tests of the lib, but more times and more intensive (we - /// want to torture it a bit). - #[test] - #[cfg_attr(miri, ignore)] // Takes like 1 or 2 infinities to run under miri - fn publish() { - const READERS: usize = 2; - for _ in 0..ITERATIONS { - let config = As::::default(); - let ended = AtomicUsize::new(0); - thread::scope(|scope| { - for _ in 0..READERS { - scope.spawn(|_| loop { - let cfg = config.load_full(); - if !cfg.is_empty() { - assert_eq!(*cfg, "New configuration"); - ended.fetch_add(1, Ordering::Relaxed); - return; - } - atomic::spin_loop_hint(); - }); - } - scope.spawn(|_| { - let new_conf = Arc::new("New configuration".to_owned()); - config.store(new_conf); - }); - }) - .unwrap(); - assert_eq!(READERS, ended.load(Ordering::Relaxed)); - let arc = config.load_full(); - assert_eq!(2, Arc::strong_count(&arc)); - assert_eq!(0, Arc::weak_count(&arc)); - } - } - - /// Similar to the doc tests of ArcSwap, but happens more times. - #[test] - fn swap_load() { - for _ in 0..100 { - let arc = Arc::new(42); - let arc_swap = As::from(Arc::clone(&arc)); - assert_eq!(42, **arc_swap.load()); - // It can be read multiple times - assert_eq!(42, **arc_swap.load()); - - // Put a new one in there - let new_arc = Arc::new(0); - assert_eq!(42, *arc_swap.swap(Arc::clone(&new_arc))); - assert_eq!(0, **arc_swap.load()); - // One loaded here, one in the arc_swap, one in new_arc - let loaded = arc_swap.load_full(); - assert_eq!(3, Arc::strong_count(&loaded)); - assert_eq!(0, Arc::weak_count(&loaded)); - // The original got released from the arc_swap - assert_eq!(1, Arc::strong_count(&arc)); - assert_eq!(0, Arc::weak_count(&arc)); - } - } - - /// Two different writers publish two series of values. The readers check that it is - /// always increasing in each serie. - /// - /// For performance, we try to reuse the threads here. - #[test] - fn multi_writers() { - let first_value = Arc::new((0, 0)); - let shared = As::from(Arc::clone(&first_value)); - const WRITER_CNT: usize = 2; - const READER_CNT: usize = 3; - #[cfg(miri)] - const ITERATIONS: usize = 5; - #[cfg(not(miri))] - const ITERATIONS: usize = 100; - const SEQ: usize = 50; - let barrier = Barrier::new(PanicMode::Poison); - thread::scope(|scope| { - for w in 0..WRITER_CNT { - // We need to move w into the closure. But we want to just reference the - // other things. - let mut barrier = barrier.clone(); - let shared = &shared; - let first_value = &first_value; - scope.spawn(move |_| { - for _ in 0..ITERATIONS { - barrier.wait(); - shared.store(Arc::clone(&first_value)); - barrier.wait(); - for i in 0..SEQ { - shared.store(Arc::new((w, i + 1))); - } - } - }); - } - for _ in 0..READER_CNT { - let mut barrier = barrier.clone(); - let shared = &shared; - let first_value = &first_value; - scope.spawn(move |_| { - for _ in 0..ITERATIONS { - barrier.wait(); - barrier.wait(); - let mut previous = [0; WRITER_CNT]; - let mut last = Arc::clone(&first_value); - loop { - let cur = shared.load(); - if Arc::ptr_eq(&last, &cur) { - atomic::spin_loop_hint(); - continue; - } - let (w, s) = **cur; - assert!(previous[w] < s, "{:?} vs {:?}", previous, cur); - previous[w] = s; - last = Guard::into_inner(cur); - if s == SEQ { - break; - } - } - } - }); - } - - drop(barrier); - }) - .unwrap(); - } - - #[test] - fn load_null() { - let shared = Aso::::default(); - let guard = shared.load(); - assert!(guard.is_none()); - shared.store(Some(Arc::new(42))); - assert_eq!(42, **shared.load().as_ref().unwrap()); - } - - #[test] - fn from_into() { - let a = Arc::new(42); - let shared = As::new(a); - let guard = shared.load(); - let a = shared.into_inner(); - assert_eq!(42, *a); - assert_eq!(2, Arc::strong_count(&a)); - drop(guard); - assert_eq!(1, Arc::strong_count(&a)); - } - - // Note on the Relaxed order here. This should be enough, because there's that - // barrier.wait in between that should do the synchronization of happens-before for us. - // And using SeqCst would probably not help either, as there's nothing else with SeqCst - // here in this test to relate it to. - #[derive(Default)] - struct ReportDrop(Arc); - impl Drop for ReportDrop { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::Relaxed); - } - } - - /// Interaction of two threads about a guard and dropping it. - /// - /// We make sure everything works in timely manner (eg. dropping of stuff) even if multiple - /// threads interact. - /// - /// The idea is: - /// * Thread 1 loads a value. - /// * Thread 2 replaces the shared value. The original value is not destroyed. - /// * Thread 1 drops the guard. The value is destroyed and this is observable in both threads. - #[test] - fn guard_drop_in_thread() { - for _ in 0..ITERATIONS { - let cnt = Arc::new(AtomicUsize::new(0)); - - let shared = As::from_pointee(ReportDrop(cnt.clone())); - assert_eq!(cnt.load(Ordering::Relaxed), 0, "Dropped prematurely"); - // We need the threads to wait for each other at places. - let sync = Barrier::new(PanicMode::Poison); - - thread::scope(|scope| { - scope.spawn({ - let sync = sync.clone(); - |_| { - let mut sync = sync; // Move into the closure - let guard = shared.load(); - sync.wait(); - // Thread 2 replaces the shared value. We wait for it to confirm. - sync.wait(); - drop(guard); - assert_eq!(cnt.load(Ordering::Relaxed), 1, "Value not dropped"); - // Let thread 2 know we already dropped it. - sync.wait(); - } - }); - - scope.spawn(|_| { - let mut sync = sync; - // Thread 1 loads, we wait for that - sync.wait(); - shared.store(Default::default()); - assert_eq!( - cnt.load(Ordering::Relaxed), - 0, - "Dropped while still in use" - ); - // Let thread 2 know we replaced it - sync.wait(); - // Thread 1 drops its guard. We wait for it to confirm. - sync.wait(); - assert_eq!(cnt.load(Ordering::Relaxed), 1, "Value not dropped"); - }); - }) - .unwrap(); - } - } - - /// Check dropping a lease in a different thread than it was created doesn't cause any - /// problems. - #[test] - fn guard_drop_in_another_thread() { - for _ in 0..ITERATIONS { - let cnt = Arc::new(AtomicUsize::new(0)); - let shared = As::from_pointee(ReportDrop(cnt.clone())); - assert_eq!(cnt.load(Ordering::Relaxed), 0, "Dropped prematurely"); - let guard = shared.load(); - - drop(shared); - assert_eq!(cnt.load(Ordering::Relaxed), 0, "Dropped prematurely"); - - thread::scope(|scope| { - scope.spawn(|_| { - drop(guard); - }); - }) - .unwrap(); - - assert_eq!(cnt.load(Ordering::Relaxed), 1, "Not dropped"); - } - } - - #[test] - fn load_option() { - let shared = Aso::from_pointee(42); - // The type here is not needed in real code, it's just addition test the type matches. - let opt: Option<_> = Guard::into_inner(shared.load()); - assert_eq!(42, *opt.unwrap()); - - shared.store(None); - assert!(shared.load().is_none()); - } - - // Check stuff can get formatted - #[test] - fn debug_impl() { - let shared = As::from_pointee(42); - assert_eq!("ArcSwapAny(42)", &format!("{:?}", shared)); - assert_eq!("42", &format!("{:?}", shared.load())); - } - - #[test] - fn display_impl() { - let shared = As::from_pointee(42); - assert_eq!("42", &format!("{}", shared)); - assert_eq!("42", &format!("{}", shared.load())); - } - - // The following "tests" are not run, only compiled. They check that things that should be - // Send/Sync actually are. - fn _check_stuff_is_send_sync() { - let shared = As::from_pointee(42); - let moved = As::from_pointee(42); - let shared_ref = &shared; - let lease = shared.load(); - let lease_ref = &lease; - let lease = shared.load(); - thread::scope(|s| { - s.spawn(move |_| { - let _ = lease; - let _ = lease_ref; - let _ = shared_ref; - let _ = moved; - }); - }) - .unwrap(); - } - - /// We have a callback in RCU. Check what happens if we access the value from within. - #[test] - fn recursive() { - let shared = ArcSwap::from(Arc::new(0)); - - shared.rcu(|i| { - if **i < 10 { - shared.rcu(|i| **i + 1); - } - **i - }); - assert_eq!(10, **shared.load()); - assert_eq!(2, Arc::strong_count(&shared.load_full())); - } - - /// A panic from within the rcu callback should not change anything. - #[test] - #[cfg(not(feature = "experimental-thread-local"))] - fn rcu_panic() { - use std::panic; - let shared = ArcSwap::from(Arc::new(0)); - assert!(panic::catch_unwind(|| shared.rcu(|_| -> usize { panic!() })).is_err()); - assert_eq!(1, Arc::strong_count(&shared.swap(Arc::new(42)))); - } - - /// Handling null/none values - #[test] - fn nulls() { - let shared = ArcSwapOption::from(Some(Arc::new(0))); - let orig = shared.swap(None); - assert_eq!(1, Arc::strong_count(&orig.unwrap())); - let null = shared.load(); - assert!(null.is_none()); - let a = Arc::new(42); - let orig = shared.compare_and_swap(ptr::null(), Some(Arc::clone(&a))); - assert!(orig.is_none()); - assert_eq!(2, Arc::strong_count(&a)); - let orig = Guard::into_inner(shared.compare_and_swap(&None::>, None)); - assert_eq!(3, Arc::strong_count(&a)); - assert!(ptr_eq(&a, &orig)); - } - - #[test] - /// Multiple RCUs interacting. - fn rcu() { - const ITERATIONS: usize = 50; - const THREADS: usize = 10; - let shared = ArcSwap::from(Arc::new(0)); - thread::scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..ITERATIONS { - shared.rcu(|old| **old + 1); - } - }); - } - }) - .unwrap(); - assert_eq!(THREADS * ITERATIONS, **shared.load()); - } - - #[test] - /// Make sure the reference count and compare_and_swap works as expected. - fn cas_ref_cnt() { - #[cfg(miri)] - const ITERATIONS: usize = 10; - #[cfg(not(miri))] - const ITERATIONS: usize = 50; - let shared = ArcSwap::from(Arc::new(0)); - for i in 0..ITERATIONS { - let orig = shared.load_full(); - assert_eq!(i, *orig); - if i % 2 == 1 { - // One for orig, one for shared - assert_eq!(2, Arc::strong_count(&orig)); - } - let n1 = Arc::new(i + 1); - // Fill up the slots sometimes - let fillup = || { - if i % 2 == 0 { - Some((0..ITERATIONS).map(|_| shared.load()).collect::>()) - } else { - None - } - }; - let guards = fillup(); - // Success - let prev = shared.compare_and_swap(&orig, Arc::clone(&n1)); - assert!(ptr_eq(&orig, &prev)); - drop(guards); - // One for orig, one for prev - assert_eq!(2, Arc::strong_count(&orig)); - // One for n1, one for shared - assert_eq!(2, Arc::strong_count(&n1)); - assert_eq!(i + 1, **shared.load()); - let n2 = Arc::new(i); - drop(prev); - let guards = fillup(); - // Failure - let prev = Guard::into_inner(shared.compare_and_swap(&orig, Arc::clone(&n2))); - drop(guards); - assert!(ptr_eq(&n1, &prev)); - // One for orig - assert_eq!(1, Arc::strong_count(&orig)); - // One for n1, one for shared, one for prev - assert_eq!(3, Arc::strong_count(&n1)); - // n2 didn't get increased - assert_eq!(1, Arc::strong_count(&n2)); - assert_eq!(i + 1, **shared.load()); - } - - let a = shared.load_full(); - // One inside shared, one for a - assert_eq!(2, Arc::strong_count(&a)); - drop(shared); - // Only a now - assert_eq!(1, Arc::strong_count(&a)); - } - } - }; -} - -t!(tests_default, DefaultStrategy); -#[cfg(all(feature = "internal-test-strategies", test))] -#[allow(deprecated)] -mod internal_strategies { - use super::*; - t!( - tests_full_slots, - crate::strategy::test_strategies::FillFastSlots - ); -} - -/// These tests assume details about the used strategy. -#[cfg(test)] -mod tests { - use super::*; - - use alloc::vec::Vec; - - /// Accessing the value inside ArcSwap with Guards (and checks for the reference - /// counts). - #[test] - fn load_cnt() { - let a = Arc::new(0); - let shared = ArcSwap::from(Arc::clone(&a)); - // One in shared, one in a - assert_eq!(2, Arc::strong_count(&a)); - let guard = shared.load(); - assert_eq!(0, **guard); - // The guard doesn't have its own ref count now - assert_eq!(2, Arc::strong_count(&a)); - let guard_2 = shared.load(); - // Unlike with guard, this does not deadlock - shared.store(Arc::new(1)); - // But now, each guard got a full Arc inside it - assert_eq!(3, Arc::strong_count(&a)); - // And when we get rid of them, they disappear - drop(guard_2); - assert_eq!(2, Arc::strong_count(&a)); - let _b = Arc::clone(&guard); - assert_eq!(3, Arc::strong_count(&a)); - // We can drop the guard it came from - drop(guard); - assert_eq!(2, Arc::strong_count(&a)); - let guard = shared.load(); - assert_eq!(1, **guard); - drop(shared); - // We can still use the guard after the shared disappears - assert_eq!(1, **guard); - let ptr = Arc::clone(&guard); - // One in shared, one in guard - assert_eq!(2, Arc::strong_count(&ptr)); - drop(guard); - assert_eq!(1, Arc::strong_count(&ptr)); - } - - /// There can be only limited amount of leases on one thread. Following ones are - /// created, but contain full Arcs. - #[test] - fn lease_overflow() { - #[cfg(miri)] - const GUARD_COUNT: usize = 100; - #[cfg(not(miri))] - const GUARD_COUNT: usize = 1000; - let a = Arc::new(0); - let shared = ArcSwap::from(Arc::clone(&a)); - assert_eq!(2, Arc::strong_count(&a)); - let mut guards = (0..GUARD_COUNT).map(|_| shared.load()).collect::>(); - let count = Arc::strong_count(&a); - assert!(count > 2); - let guard = shared.load(); - assert_eq!(count + 1, Arc::strong_count(&a)); - drop(guard); - assert_eq!(count, Arc::strong_count(&a)); - // When we delete the first one, it didn't have an Arc in it, so the ref count - // doesn't drop - guards.swap_remove(0); - assert_eq!(count, Arc::strong_count(&a)); - // But new one reuses now vacant the slot and doesn't create a new Arc - let _guard = shared.load(); - assert_eq!(count, Arc::strong_count(&a)); - } -} diff --git a/third-party/vendor/arc-swap/src/ref_cnt.rs b/third-party/vendor/arc-swap/src/ref_cnt.rs deleted file mode 100644 index f70a5893..00000000 --- a/third-party/vendor/arc-swap/src/ref_cnt.rs +++ /dev/null @@ -1,176 +0,0 @@ -use core::mem; -use core::ptr; - -use alloc::rc::Rc; -use alloc::sync::Arc; - -/// A trait describing smart reference counted pointers. -/// -/// Note that in a way [`Option>`][Option] is also a smart reference counted pointer, just -/// one that can hold NULL. -/// -/// The trait is unsafe, because a wrong implementation will break the [ArcSwapAny] -/// implementation and lead to UB. -/// -/// This is not actually expected for downstream crate to implement, this is just means to reuse -/// code for [Arc] and [`Option`][Option] variants. However, it is theoretically possible (if -/// you have your own [Arc] implementation). -/// -/// It is also implemented for [Rc], but that is not considered very useful (because the -/// [ArcSwapAny] is not `Send` or `Sync`, therefore there's very little advantage for it to be -/// atomic). -/// -/// # Safety -/// -/// Aside from the obvious properties (like that incrementing and decrementing a reference count -/// cancel each out and that having less references tracked than how many things actually point to -/// the value is fine as long as the count doesn't drop to 0), it also must satisfy that if two -/// pointers have the same value, they point to the same object. This is specifically not true for -/// ZSTs, but it is true for `Arc`s of ZSTs, because they have the reference counts just after the -/// value. It would be fine to point to a type-erased version of the same object, though (if one -/// could use this trait with unsized types in the first place). -/// -/// Furthermore, the type should be Pin (eg. if the type is cloned or moved, it should still -/// point/deref to the same place in memory). -/// -/// [Arc]: std::sync::Arc -/// [Rc]: std::rc::Rc -/// [ArcSwapAny]: crate::ArcSwapAny -pub unsafe trait RefCnt: Clone { - /// The base type the pointer points to. - type Base; - - /// Converts the smart pointer into a raw pointer, without affecting the reference count. - /// - /// This can be seen as kind of freezing the pointer ‒ it'll be later converted back using - /// [`from_ptr`](#method.from_ptr). - /// - /// The pointer must point to the value stored (and the value must be the same as one returned - /// by [`as_ptr`](#method.as_ptr). - fn into_ptr(me: Self) -> *mut Self::Base; - - /// Provides a view into the smart pointer as a raw pointer. - /// - /// This must not affect the reference count ‒ the pointer is only borrowed. - fn as_ptr(me: &Self) -> *mut Self::Base; - - /// Converts a raw pointer back into the smart pointer, without affecting the reference count. - /// - /// This is only called on values previously returned by [`into_ptr`](#method.into_ptr). - /// However, it is not guaranteed to be 1:1 relation ‒ `from_ptr` may be called more times than - /// `into_ptr` temporarily provided the reference count never drops under 1 during that time - /// (the implementation sometimes owes a reference). These extra pointers will either be - /// converted back using `into_ptr` or forgotten. - /// - /// # Safety - /// - /// This must not be called by code outside of this crate. - unsafe fn from_ptr(ptr: *const Self::Base) -> Self; - - /// Increments the reference count by one. - /// - /// Return the pointer to the inner thing as a side effect. - fn inc(me: &Self) -> *mut Self::Base { - Self::into_ptr(Self::clone(me)) - } - - /// Decrements the reference count by one. - /// - /// Note this is called on a raw pointer (one previously returned by - /// [`into_ptr`](#method.into_ptr). This may lead to dropping of the reference count to 0 and - /// destruction of the internal pointer. - /// - /// # Safety - /// - /// This must not be called by code outside of this crate. - unsafe fn dec(ptr: *const Self::Base) { - drop(Self::from_ptr(ptr)); - } -} - -unsafe impl RefCnt for Arc { - type Base = T; - fn into_ptr(me: Arc) -> *mut T { - Arc::into_raw(me) as *mut T - } - fn as_ptr(me: &Arc) -> *mut T { - // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same - // intention as - // - // me as &T as *const T as *mut T - // - // We first create a "shallow copy" of me - one that doesn't really own its ref count - // (that's OK, me _does_ own it, so it can't be destroyed in the meantime). - // Then we can use into_raw (which preserves not having the ref count). - // - // We need to "revert" the changes we did. In current std implementation, the combination - // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw - // and that read shall be paired with forget to properly "close the brackets". In future - // versions of STD, these may become something else that's not really no-op (unlikely, but - // possible), so we future-proof it a bit. - - // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads - let ptr = Arc::into_raw(unsafe { ptr::read(me) }); - let ptr = ptr as *mut T; - - // SAFETY: We got the pointer from into_raw just above - mem::forget(unsafe { Arc::from_raw(ptr) }); - - ptr - } - unsafe fn from_ptr(ptr: *const T) -> Arc { - Arc::from_raw(ptr) - } -} - -unsafe impl RefCnt for Rc { - type Base = T; - fn into_ptr(me: Rc) -> *mut T { - Rc::into_raw(me) as *mut T - } - fn as_ptr(me: &Rc) -> *mut T { - // Slightly convoluted way to do this, but this avoids stacked borrows violations. The same - // intention as - // - // me as &T as *const T as *mut T - // - // We first create a "shallow copy" of me - one that doesn't really own its ref count - // (that's OK, me _does_ own it, so it can't be destroyed in the meantime). - // Then we can use into_raw (which preserves not having the ref count). - // - // We need to "revert" the changes we did. In current std implementation, the combination - // of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw - // and that read shall be paired with forget to properly "close the brackets". In future - // versions of STD, these may become something else that's not really no-op (unlikely, but - // possible), so we future-proof it a bit. - - // SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads - let ptr = Rc::into_raw(unsafe { ptr::read(me) }); - let ptr = ptr as *mut T; - - // SAFETY: We got the pointer from into_raw just above - mem::forget(unsafe { Rc::from_raw(ptr) }); - - ptr - } - unsafe fn from_ptr(ptr: *const T) -> Rc { - Rc::from_raw(ptr) - } -} - -unsafe impl RefCnt for Option { - type Base = T::Base; - fn into_ptr(me: Option) -> *mut T::Base { - me.map(T::into_ptr).unwrap_or_else(ptr::null_mut) - } - fn as_ptr(me: &Option) -> *mut T::Base { - me.as_ref().map(T::as_ptr).unwrap_or_else(ptr::null_mut) - } - unsafe fn from_ptr(ptr: *const T::Base) -> Option { - if ptr.is_null() { - None - } else { - Some(T::from_ptr(ptr)) - } - } -} diff --git a/third-party/vendor/arc-swap/src/serde.rs b/third-party/vendor/arc-swap/src/serde.rs deleted file mode 100644 index 95ecf3f0..00000000 --- a/third-party/vendor/arc-swap/src/serde.rs +++ /dev/null @@ -1,132 +0,0 @@ -use crate::{ArcSwapAny, RefCnt, Strategy}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -impl Serialize for ArcSwapAny -where - T: RefCnt + Serialize, - S: Strategy, -{ - fn serialize(&self, serializer: Ser) -> Result { - self.load().serialize(serializer) - } -} - -impl<'de, T, S> Deserialize<'de> for ArcSwapAny -where - T: RefCnt + Deserialize<'de>, - S: Strategy + Default, -{ - fn deserialize>(deserializer: D) -> Result { - Ok(Self::from(T::deserialize(deserializer)?)) - } -} - -#[cfg(test)] -mod tests { - use crate::{ArcSwap, ArcSwapAny, ArcSwapOption, RefCnt}; - use serde_derive::{Deserialize, Serialize}; - use serde_test::{assert_tokens, Token}; - use std::sync::Arc; - - #[derive(Debug, Serialize, Deserialize)] - #[serde(transparent)] - struct ArcSwapAnyEq(ArcSwapAny); - impl PartialEq for ArcSwapAnyEq { - fn eq(&self, other: &Self) -> bool { - self.0.load().eq(&other.0.load()) - } - } - impl Eq for ArcSwapAnyEq {} - - #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] - struct Foo { - field0: u64, - field1: String, - } - - #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] - struct Bar { - field0: ArcSwapAnyEq>, - field1: ArcSwapAnyEq>>, - } - - #[test] - fn test_serialize_deserialize() { - let field0 = u64::MAX; - let field1 = "FOO_-0123456789"; - - let data_orig = Foo { - field0, - field1: field1.to_string(), - }; - let data = ArcSwapAnyEq(ArcSwap::from_pointee(data_orig)); - assert_tokens( - &data, - &[ - Token::Struct { - name: "Foo", - len: 2, - }, - Token::Str("field0"), - Token::U64(u64::MAX), - Token::Str("field1"), - Token::String(field1), - Token::StructEnd, - ], - ); - - let data = Bar { - field0: ArcSwapAnyEq(ArcSwap::from_pointee(field0)), - field1: ArcSwapAnyEq(ArcSwapOption::from_pointee(field1.to_string())), - }; - assert_tokens( - &data, - &[ - Token::Struct { - name: "Bar", - len: 2, - }, - Token::Str("field0"), - Token::U64(u64::MAX), - Token::Str("field1"), - Token::Some, - Token::String(field1), - Token::StructEnd, - ], - ); - } - - #[test] - fn test_serialize_deserialize_option() { - let field0 = u64::MAX; - let field1 = "FOO_-0123456789"; - - let data_orig = Foo { - field0, - field1: field1.to_string(), - }; - let data = ArcSwapAnyEq(ArcSwapOption::from_pointee(data_orig)); - assert_tokens( - &data, - &[ - Token::Some, - Token::Struct { - name: "Foo", - len: 2, - }, - Token::Str("field0"), - Token::U64(u64::MAX), - Token::Str("field1"), - Token::String(field1), - Token::StructEnd, - ], - ); - } - - #[test] - fn test_serialize_deserialize_option_none() { - let data = ArcSwapAnyEq(ArcSwapOption::::from_pointee(None)); - - assert_tokens(&data, &[Token::None]); - } -} diff --git a/third-party/vendor/arc-swap/src/strategy/hybrid.rs b/third-party/vendor/arc-swap/src/strategy/hybrid.rs deleted file mode 100644 index 2c18f967..00000000 --- a/third-party/vendor/arc-swap/src/strategy/hybrid.rs +++ /dev/null @@ -1,235 +0,0 @@ -//! A hybrid strategy. -//! -//! This is based on debts ‒ an Arc may owe a reference, but it is marked in the debt. It is either -//! put back (by stopping using it), or if the pointer is replaced, the writer bumps the reference -//! count and removes the debt. -//! -//! The strategy uses two different slots for the debts. The first ones are faster, but fallible. -//! If they fail (either because there's interference from a writer at the same time, or because -//! they are full), the secondary one that is slower, but always succeeds, is used. In the latter -//! case, the reference is bumped and this secondary debt slot is released, so it is available for -//! further loads. -//! -//! See the [crate::debt] module for the actual slot manipulation. Here we just wrap them into the -//! strategy. - -use core::borrow::Borrow; -use core::mem::{self, ManuallyDrop}; -use core::ops::Deref; -use core::ptr; -use core::sync::atomic::AtomicPtr; -use core::sync::atomic::Ordering::*; - -use super::sealed::{CaS, InnerStrategy, Protected}; -use crate::debt::{Debt, LocalNode}; -use crate::ref_cnt::RefCnt; - -pub struct HybridProtection { - debt: Option<&'static Debt>, - ptr: ManuallyDrop, -} - -impl HybridProtection { - pub(super) unsafe fn new(ptr: *const T::Base, debt: Option<&'static Debt>) -> Self { - Self { - debt, - ptr: ManuallyDrop::new(T::from_ptr(ptr)), - } - } - - /// Try getting a dept into a fast slot. - #[inline] - fn attempt(node: &LocalNode, storage: &AtomicPtr) -> Option { - // Relaxed is good enough here, see the Acquire below - let ptr = storage.load(Relaxed); - // Try to get a debt slot. If not possible, fail. - let debt = node.new_fast(ptr as usize)?; - - // Acquire to get the data. - // - // SeqCst to make sure the storage vs. the debt are well ordered. - let confirm = storage.load(SeqCst); - if ptr == confirm { - // Successfully got a debt - Some(unsafe { Self::new(ptr, Some(debt)) }) - } else if debt.pay::(ptr) { - // It changed in the meantime, we return the debt (that is on the outdated pointer, - // possibly destroyed) and fail. - None - } else { - // It changed in the meantime, but the debt for the previous pointer was already paid - // for by someone else, so we are fine using it. - Some(unsafe { Self::new(ptr, None) }) - } - } - - /// Get a debt slot using the slower but always successful mechanism. - fn fallback(node: &LocalNode, storage: &AtomicPtr) -> Self { - // First, we claim a debt slot and store the address of the atomic pointer there, so the - // writer can optionally help us out with loading and protecting something. - let gen = node.new_helping(storage as *const _ as usize); - // We already synchronized the start of the sequence by SeqCst in the new_helping vs swap on - // the pointer. We just need to make sure to bring the pointee in (this can be newer than - // what we got in the Debt) - let candidate = storage.load(Acquire); - - // Try to replace the debt with our candidate. If it works, we get the debt slot to use. If - // not, we get a replacement value, already protected and a debt to take care of. - match node.confirm_helping(gen, candidate as usize) { - Ok(debt) => { - // The fast path -> we got the debt confirmed alright. - Self::from_inner(unsafe { Self::new(candidate, Some(debt)).into_inner() }) - } - Err((unused_debt, replacement)) => { - // The debt is on the candidate we provided and it is unused, we so we just pay it - // back right away. - if !unused_debt.pay::(candidate) { - unsafe { T::dec(candidate) }; - } - // We got a (possibly) different pointer out. But that one is already protected and - // the slot is paid back. - unsafe { Self::new(replacement as *mut _, None) } - } - } - } - - #[inline] - fn as_ptr(&self) -> *const T::Base { - T::as_ptr(self.ptr.deref()) - } -} - -impl Drop for HybridProtection { - #[inline] - fn drop(&mut self) { - match self.debt.take() { - // We have our own copy of Arc, so we don't need a protection. Do nothing (but release - // the Arc below). - None => (), - // If we owed something, just return the debt. We don't have a pointer owned, so - // nothing to release. - Some(debt) => { - let ptr = T::as_ptr(&self.ptr); - if debt.pay::(ptr) { - return; - } - // But if the debt was already paid for us, we need to release the pointer, as we - // were effectively already in the Unprotected mode. - } - } - // Equivalent to T::dec(ptr) - unsafe { ManuallyDrop::drop(&mut self.ptr) }; - } -} - -impl Protected for HybridProtection { - #[inline] - fn from_inner(ptr: T) -> Self { - Self { - debt: None, - ptr: ManuallyDrop::new(ptr), - } - } - - #[inline] - fn into_inner(mut self) -> T { - // Drop any debt and release any lock held by the given guard and return a - // full-featured value that even can outlive the ArcSwap it originated from. - match self.debt.take() { - None => (), // We have a fully loaded ref-counted pointer. - Some(debt) => { - let ptr = T::inc(&self.ptr); - if !debt.pay::(ptr) { - unsafe { T::dec(ptr) }; - } - } - } - - // The ptr::read & forget is something like a cheating move. We can't move it out, because - // we have a destructor and Rust doesn't allow us to do that. - let inner = unsafe { ptr::read(self.ptr.deref()) }; - mem::forget(self); - inner - } -} - -impl Borrow for HybridProtection { - #[inline] - fn borrow(&self) -> &T { - &self.ptr - } -} - -pub trait Config { - // Mostly for testing, way to disable the fast slo - const USE_FAST: bool; -} - -#[derive(Clone, Default)] -pub struct DefaultConfig; - -impl Config for DefaultConfig { - const USE_FAST: bool = true; -} - -#[derive(Clone, Default)] -pub struct HybridStrategy { - pub(crate) _config: Cfg, -} - -impl InnerStrategy for HybridStrategy -where - T: RefCnt, - Cfg: Config, -{ - type Protected = HybridProtection; - unsafe fn load(&self, storage: &AtomicPtr) -> Self::Protected { - LocalNode::with(|node| { - let fast = if Cfg::USE_FAST { - HybridProtection::attempt(node, storage) - } else { - None - }; - fast.unwrap_or_else(|| HybridProtection::fallback(node, storage)) - }) - } - unsafe fn wait_for_readers(&self, old: *const T::Base, storage: &AtomicPtr) { - // The pay_all may need to provide fresh replacement values if someone else is loading from - // this particular storage. We do so by the exact same way, by `load` ‒ it's OK, a writer - // does not hold a slot and the reader doesn't recurse back into writer, so we won't run - // out of slots. - let replacement = || self.load(storage).into_inner(); - Debt::pay_all::(old, storage as *const _ as usize, replacement); - } -} - -impl CaS for HybridStrategy { - unsafe fn compare_and_swap>( - &self, - storage: &AtomicPtr, - current: C, - new: T, - ) -> Self::Protected { - loop { - let old = >::load(self, storage); - // Observation of their inequality is enough to make a verdict - if old.as_ptr() != current.as_raw() { - return old; - } - // If they are still equal, put the new one in. - let new_raw = T::as_ptr(&new); - if storage - .compare_exchange_weak(current.as_raw(), new_raw, SeqCst, Relaxed) - .is_ok() - { - // We successfully put the new value in. The ref count went in there too. - T::into_ptr(new); - >::wait_for_readers(self, old.as_ptr(), storage); - // We just got one ref count out of the storage and we have one in old. We don't - // need two. - T::dec(old.as_ptr()); - return old; - } - } - } -} diff --git a/third-party/vendor/arc-swap/src/strategy/mod.rs b/third-party/vendor/arc-swap/src/strategy/mod.rs deleted file mode 100644 index 50bdada8..00000000 --- a/third-party/vendor/arc-swap/src/strategy/mod.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! Strategies for protecting the reference counts. -//! -//! There are multiple algorithms how to protect the reference counts while they're being updated -//! by multiple threads, each with its own set of pros and cons. The [`DefaultStrategy`] is used by -//! default and should generally be the least surprising option. It is possible to pick a different -//! strategy. -//! -//! For now, the traits in here are sealed and don't expose any methods to the users of the crate. -//! This is because we are not confident about the details just yet. In the future it may be -//! possible for downstream users to implement their own, but for now it is only so users can -//! choose one of the provided. -//! -//! It is expected that future strategies would come with different capabilities and limitations. -//! In particular, some that are not "tight" in the cleanup (delay the cleanup) or not support the -//! compare and swap operations. -//! -//! Currently, we have these strategies: -//! -//! * [`DefaultStrategy`] (this one is used implicitly) -//! * [`RwLock<()>`][std::sync::RwLock] -//! -//! # Testing -//! -//! Formally, the [`RwLock<()>`][std::sync::RwLock] may be used as a strategy too. It doesn't have -//! the performance characteristics or lock-free guarantees of the others, but it is much simpler -//! and contains less `unsafe` code (actually, less code altogether). Therefore, it can be used for -//! testing purposes and cross-checking. -//! -//! Note that generally, using [`RwLock>`][std::sync::RwLock] is likely to be better -//! performance wise. So if the goal is to not use third-party unsafe code, only the one in -//! [`std`], that is the better option. This is provided mostly for investigation and testing of -//! [`ArcSwap`] itself or algorithms written to use [`ArcSwap`]. -//! -//! *This is not meant to be used in production code*. -//! -//! [`ArcSwap`]: crate::ArcSwap -//! [`load`]: crate::ArcSwapAny::load - -use core::borrow::Borrow; -use core::sync::atomic::AtomicPtr; - -use crate::ref_cnt::RefCnt; - -pub(crate) mod hybrid; - -#[cfg(all( - feature = "internal-test-strategies", - feature = "experimental-thread-local" -))] -compile_error!("experimental-thread-local is incompatible with internal-test-strategies as it enables #[no_std]"); - -#[cfg(feature = "internal-test-strategies")] -mod rw_lock; -// Do not use from outside of the crate. -#[cfg(feature = "internal-test-strategies")] -#[doc(hidden)] -pub mod test_strategies; - -use self::hybrid::{DefaultConfig, HybridStrategy}; - -/// The default strategy. -/// -/// It is used by the type aliases [`ArcSwap`][crate::ArcSwap] and -/// [`ArcSwapOption`][crate::ArcSwapOption]. Only the other strategies need to be used explicitly. -/// -/// # Performance characteristics -/// -/// * It is optimized for read-heavy situations, with possibly many concurrent read accesses from -/// multiple threads. Readers don't contend each other at all. -/// * Readers are wait-free (with the exception of at most once in `usize::MAX / 4` accesses, which -/// is only lock-free). -/// * Writers are lock-free. -/// * Reclamation is exact ‒ the resource is released as soon as possible (works like RAII, not -/// like a traditional garbage collector; can contain non-`'static` data). -/// -/// Each thread has a limited number of fast slots (currently 8, but the exact number is not -/// guaranteed). If it holds at most that many [`Guard`]s at once, acquiring them is fast. Once -/// these slots are used up (by holding to these many [`Guard`]s), acquiring more of them will be -/// slightly slower, but still wait-free. -/// -/// If you expect to hold a lot of "handles" to the data around, or hold onto it for a long time, -/// you may want to prefer the [`load_full`][crate::ArcSwapAny::load_full] method. -/// -/// The speed of the fast slots is in the ballpark of locking an *uncontented* mutex. The advantage -/// over the mutex is the stability of speed in the face of contention from other threads ‒ while -/// the performance of mutex goes rapidly down, the slowdown of running out of held slots or heavy -/// concurrent writer thread in the area of single-digit multiples. -/// -/// The ballpark benchmark figures (my older computer) are around these, but you're welcome to run -/// the benchmarks in the git repository or write your own. -/// -/// * Load (both uncontented and contented by other loads): ~30ns -/// * `load_full`: ~50ns uncontented, goes up a bit with other `load_full` in other threads on the -/// same `Arc` value (~80-100ns). -/// * Loads after running out of the slots ‒ about 10-20ns slower than `load_full`. -/// * Stores: Dependent on number of threads, but generally low microseconds. -/// * Loads with heavy concurrent writer (to the same `ArcSwap`): ~250ns. -/// -/// [`load`]: crate::ArcSwapAny::load -/// [`Guard`]: crate::Guard -pub type DefaultStrategy = HybridStrategy; - -/// Strategy for isolating instances. -/// -/// It is similar to [`DefaultStrategy`], however the spin lock is not sharded (therefore multiple -/// concurrent threads might get bigger hit when multiple threads have to fall back). Nevertheless, -/// each instance has a private spin lock, not influencing the other instances. That also makes -/// them bigger in memory. -/// -/// The hazard pointers are still shared between all instances. -/// -/// The purpose of this strategy is meant for cases where a single instance is going to be -/// "tortured" a lot, so it should not overflow to other instances. -/// -/// This too may be changed for something else (but with at least as good guarantees, primarily -/// that other instances won't get influenced by the "torture"). -// Testing if the DefaultStrategy is good enough to replace it fully and then deprecate. -#[doc(hidden)] -pub type IndependentStrategy = DefaultStrategy; - -// TODO: When we are ready to un-seal, should these traits become unsafe? - -pub(crate) mod sealed { - use super::*; - use crate::as_raw::AsRaw; - - pub trait Protected: Borrow { - fn into_inner(self) -> T; - fn from_inner(ptr: T) -> Self; - } - - pub trait InnerStrategy { - // Drop „unlocks“ - type Protected: Protected; - unsafe fn load(&self, storage: &AtomicPtr) -> Self::Protected; - unsafe fn wait_for_readers(&self, old: *const T::Base, storage: &AtomicPtr); - } - - pub trait CaS: InnerStrategy { - unsafe fn compare_and_swap>( - &self, - storage: &AtomicPtr, - current: C, - new: T, - ) -> Self::Protected; - } -} - -/// A strategy for protecting the reference counted pointer `T`. -/// -/// This chooses the algorithm for how the reference counts are protected. Note that the user of -/// the crate can't implement the trait and can't access any method; this is hopefully temporary -/// measure to make sure the interface is not part of the stability guarantees of the crate. Once -/// enough experience is gained with implementing various strategies, it will be un-sealed and -/// users will be able to provide their own implementation. -/// -/// For now, the trait works only as a bound to talk about the types that represent strategies. -pub trait Strategy: sealed::InnerStrategy {} -impl> Strategy for S {} - -/// An extension of the [`Strategy`], allowing for compare and swap operation. -/// -/// The compare and swap operation is "advanced" and not all strategies need to support them. -/// Therefore, it is a separate trait. -/// -/// Similarly, it is not yet made publicly usable or implementable and works only as a bound. -pub trait CaS: sealed::CaS {} -impl> CaS for S {} diff --git a/third-party/vendor/arc-swap/src/strategy/rw_lock.rs b/third-party/vendor/arc-swap/src/strategy/rw_lock.rs deleted file mode 100644 index 31506bb4..00000000 --- a/third-party/vendor/arc-swap/src/strategy/rw_lock.rs +++ /dev/null @@ -1,63 +0,0 @@ -use core::sync::atomic::{AtomicPtr, Ordering}; - -use std::sync::RwLock; - -use super::sealed::{CaS, InnerStrategy, Protected}; -use crate::as_raw::AsRaw; -use crate::ref_cnt::RefCnt; - -impl Protected for T { - #[inline] - fn from_inner(ptr: T) -> Self { - ptr - } - - #[inline] - fn into_inner(self) -> T { - self - } -} - -impl InnerStrategy for RwLock<()> { - type Protected = T; - unsafe fn load(&self, storage: &AtomicPtr) -> T { - let _guard = self.read().expect("We don't panic in here"); - let ptr = storage.load(Ordering::Acquire); - let ptr = T::from_ptr(ptr as *const T::Base); - T::inc(&ptr); - - ptr - } - - unsafe fn wait_for_readers(&self, _: *const T::Base, _: &AtomicPtr) { - // By acquiring the write lock, we make sure there are no read locks present across it. - drop(self.write().expect("We don't panic in here")); - } -} - -impl CaS for RwLock<()> { - unsafe fn compare_and_swap>( - &self, - storage: &AtomicPtr, - current: C, - new: T, - ) -> Self::Protected { - let _lock = self.write(); - let cur = current.as_raw(); - let new = T::into_ptr(new); - let swapped = storage.compare_exchange(cur, new, Ordering::AcqRel, Ordering::Relaxed); - let old = match swapped { - Ok(old) => old, - Err(old) => old, - }; - let old = T::from_ptr(old as *const T::Base); - if swapped.is_err() { - // If the new didn't go in, we need to destroy it and increment count in the old that - // we just duplicated - T::inc(&old); - drop(T::from_ptr(new)); - } - drop(current); - old - } -} diff --git a/third-party/vendor/arc-swap/src/strategy/test_strategies.rs b/third-party/vendor/arc-swap/src/strategy/test_strategies.rs deleted file mode 100644 index 76bffd2e..00000000 --- a/third-party/vendor/arc-swap/src/strategy/test_strategies.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![deprecated(note = "Only for internal testing. Do not use")] -#![allow(deprecated)] // We need to allow ourselves the stuff we deprecate here. -//! Some strategies for internal testing. -//! -//! # Warning -//! -//! They come with no guarantees of correctness, stability, performance or anything at all. *DO NOT -//! USE*. - -use super::hybrid::{Config, HybridStrategy}; - -/// Config for no fast slots. -#[derive(Clone, Copy, Default)] -pub struct NoFastSlots; - -impl Config for NoFastSlots { - const USE_FAST: bool = false; -} - -/// A strategy that fills the slots with some crap to make sure we test the fallbacks too. -#[deprecated(note = "Only for internal testing. Do not use")] -pub type FillFastSlots = HybridStrategy; diff --git a/third-party/vendor/arc-swap/src/weak.rs b/third-party/vendor/arc-swap/src/weak.rs deleted file mode 100644 index 2b8d8572..00000000 --- a/third-party/vendor/arc-swap/src/weak.rs +++ /dev/null @@ -1,118 +0,0 @@ -use core::ptr; - -use alloc::rc::Weak as RcWeak; -use alloc::sync::Weak; - -use crate::RefCnt; - -unsafe impl RefCnt for Weak { - type Base = T; - fn as_ptr(me: &Self) -> *mut T { - if Weak::ptr_eq(&Weak::new(), me) { - ptr::null_mut() - } else { - Weak::as_ptr(me) as *mut T - } - } - fn into_ptr(me: Self) -> *mut T { - if Weak::ptr_eq(&Weak::new(), &me) { - ptr::null_mut() - } else { - Weak::into_raw(me) as *mut T - } - } - unsafe fn from_ptr(ptr: *const T) -> Self { - if ptr.is_null() { - Weak::new() - } else { - Weak::from_raw(ptr) - } - } -} - -unsafe impl RefCnt for RcWeak { - type Base = T; - fn as_ptr(me: &Self) -> *mut T { - if RcWeak::ptr_eq(&RcWeak::new(), me) { - ptr::null_mut() - } else { - RcWeak::as_ptr(me) as *mut T - } - } - fn into_ptr(me: Self) -> *mut T { - if RcWeak::ptr_eq(&RcWeak::new(), &me) { - ptr::null_mut() - } else { - RcWeak::into_raw(me) as *mut T - } - } - unsafe fn from_ptr(ptr: *const T) -> Self { - if ptr.is_null() { - RcWeak::new() - } else { - RcWeak::from_raw(ptr) - } - } -} - -macro_rules! t { - ($name: ident, $strategy: ty) => { - #[cfg(test)] - mod $name { - use alloc::sync::{Arc, Weak}; - - use crate::ArcSwapAny; - - #[allow(deprecated)] // We use "deprecated" testing strategies in here. - type ArcSwapWeak = ArcSwapAny, $strategy>; - - // Convert to weak, push it through the shared and pull it out again. - #[test] - fn there_and_back() { - let data = Arc::new("Hello"); - let shared = ArcSwapWeak::new(Arc::downgrade(&data)); - assert_eq!(1, Arc::strong_count(&data)); - assert_eq!(1, Arc::weak_count(&data)); - let weak = shared.load(); - assert_eq!("Hello", *weak.upgrade().unwrap()); - assert!(Arc::ptr_eq(&data, &weak.upgrade().unwrap())); - } - - // Replace a weak pointer with a NULL one - #[test] - fn reset() { - let data = Arc::new("Hello"); - let shared = ArcSwapWeak::new(Arc::downgrade(&data)); - assert_eq!(1, Arc::strong_count(&data)); - assert_eq!(1, Arc::weak_count(&data)); - - // An empty weak (eg. NULL) - shared.store(Weak::new()); - assert_eq!(1, Arc::strong_count(&data)); - assert_eq!(0, Arc::weak_count(&data)); - - let weak = shared.load(); - assert!(weak.upgrade().is_none()); - } - - // Destroy the underlying data while the weak is still stored inside. Should make it go - // NULL-ish - #[test] - fn destroy() { - let data = Arc::new("Hello"); - let shared = ArcSwapWeak::new(Arc::downgrade(&data)); - - drop(data); - let weak = shared.load(); - assert!(weak.upgrade().is_none()); - } - } - }; -} - -t!(tests_default, crate::DefaultStrategy); -#[cfg(feature = "internal-test-strategies")] -t!( - tests_full_slots, - crate::strategy::test_strategies::FillFastSlots -); diff --git a/third-party/vendor/arc-swap/tests/random.rs b/third-party/vendor/arc-swap/tests/random.rs deleted file mode 100644 index 5d8d32cf..00000000 --- a/third-party/vendor/arc-swap/tests/random.rs +++ /dev/null @@ -1,125 +0,0 @@ -//! Let it torture the implementation with some randomized operations. - -use std::mem; -use std::sync::Arc; - -use arc_swap::{ArcSwapAny, DefaultStrategy, IndependentStrategy}; -use once_cell::sync::Lazy; -use proptest::prelude::*; - -#[derive(Copy, Clone, Debug)] -enum OpsInstruction { - Store(usize), - Swap(usize), - LoadFull, - Load, -} - -impl OpsInstruction { - fn random() -> impl Strategy { - prop_oneof![ - any::().prop_map(Self::Store), - any::().prop_map(Self::Swap), - Just(Self::LoadFull), - Just(Self::Load), - ] - } -} - -proptest! {} - -const LIMIT: usize = 5; -#[cfg(not(miri))] -const SIZE: usize = 100; -#[cfg(miri)] -const SIZE: usize = 10; -static ARCS: Lazy>> = Lazy::new(|| (0..LIMIT).map(Arc::new).collect()); - -#[derive(Copy, Clone, Debug)] -enum SelInstruction { - Swap(usize), - Cas(usize, usize), -} - -impl SelInstruction { - fn random() -> impl Strategy { - prop_oneof![ - (0..LIMIT).prop_map(Self::Swap), - (0..LIMIT, 0..LIMIT).prop_map(|(cur, new)| Self::Cas(cur, new)), - ] - } -} - -// Generate the same tests for bunch of strategies (one module for one strategy) -macro_rules! t { - (@full => $name: ident, $strategy: ty) => { - t!(@compose => $name, $strategy, - #[test] - fn selection( - instructions in proptest::collection::vec(SelInstruction::random(), 1..SIZE), - ) { - let mut bare = Arc::clone(&ARCS[0]); - #[allow(deprecated)] // We use "deprecated" testing strategies in here. - let a = ArcSwapAny::<_, $strategy>::from(Arc::clone(&ARCS[0])); - for ins in instructions { - match ins { - SelInstruction::Swap(idx) => { - let expected = mem::replace(&mut bare, Arc::clone(&ARCS[idx])); - let actual = a.swap(Arc::clone(&ARCS[idx])); - assert!(Arc::ptr_eq(&expected, &actual)); - } - SelInstruction::Cas(cur, new) => { - let expected = Arc::clone(&bare); - if bare == ARCS[cur] { - bare = Arc::clone(&ARCS[new]); - } - let actual = a.compare_and_swap(&ARCS[cur], Arc::clone(&ARCS[new])); - assert!(Arc::ptr_eq(&expected, &actual)); - } - } - } - } - ); - }; - (@nocas => $name: ident, $strategy: ty) => { - t!(@compose => $name, $strategy, ); - }; - (@compose => $name: ident, $strategy: ty, $($extra: tt)*) => { - mod $name { - use super::*; - - proptest! { - $($extra)* - - #[test] - fn ops( - instructions in proptest::collection::vec(OpsInstruction::random(), 1..SIZE), - ) { - use crate::OpsInstruction::*; - let mut m = 0; - #[allow(deprecated)] // We use "deprecated" testing strategies in here. - let a = ArcSwapAny::<_, $strategy>::new(Arc::new(0usize)); - for ins in instructions { - match ins { - Store(v) => { - m = v; - a.store(Arc::new(v)); - } - Swap(v) => { - let old = mem::replace(&mut m, v); - assert_eq!(old, *a.swap(Arc::new(v))); - } - Load => assert_eq!(m, **a.load()), - LoadFull => assert_eq!(m, *a.load_full()), - } - } - } - } - } - }; -} - -t!(@full => default, DefaultStrategy); -t!(@full => independent, IndependentStrategy); -#[cfg(feature = "internal-test-strategies")] -t!(@full => full_slots, arc_swap::strategy::test_strategies::FillFastSlots); diff --git a/third-party/vendor/arc-swap/tests/stress.rs b/third-party/vendor/arc-swap/tests/stress.rs deleted file mode 100644 index 15e60fc7..00000000 --- a/third-party/vendor/arc-swap/tests/stress.rs +++ /dev/null @@ -1,310 +0,0 @@ -//! Stress-tests -//! -//! The tests in here try to torture the implementation with multiple threads, in an attempt to -//! discover any possible race condition. - -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::{Arc, Mutex, MutexGuard, PoisonError}; - -use adaptive_barrier::{Barrier, PanicMode}; -use arc_swap::strategy::{CaS, DefaultStrategy, IndependentStrategy, Strategy}; -use arc_swap::ArcSwapAny; -use crossbeam_utils::thread; -use itertools::Itertools; -use once_cell::sync::Lazy; - -static LOCK: Lazy> = Lazy::new(|| Mutex::new(())); - -/// We want to prevent these tests from running concurrently, because they run multi-threaded. -fn lock() -> MutexGuard<'static, ()> { - LOCK.lock().unwrap_or_else(PoisonError::into_inner) -} - -struct LLNode>>>> { - next: ArcSwapAny>>, S>, - num: usize, - owner: usize, -} - -/// A test that repeatedly builds a linked list concurrently with multiple threads. -/// -/// The idea here is to stress-test the RCU implementation and see that no items get lost and that -/// the ref counts are correct afterwards. -fn storm_link_list(node_cnt: usize, iters: usize) -where - S: Default + CaS>>> + Send + Sync, -{ - let _lock = lock(); - let head = ArcSwapAny::<_, S>::from(None::>>); - #[cfg(not(miri))] - let cpus = num_cpus::get(); - #[cfg(miri)] - let cpus = 2; - let barr = Barrier::new(PanicMode::Poison); - thread::scope(|scope| { - for thread in 0..cpus { - // We want to borrow these, but that kind-of conflicts with the move closure mode - let mut barr = barr.clone(); - let head = &head; - scope.spawn(move |_| { - let nodes = (0..node_cnt) - .map(|i| LLNode { - next: ArcSwapAny::from(None), - num: i, - owner: thread, - }) - .map(Arc::new) - .collect::>(); - for iter in 0..iters { - barr.wait(); // Start synchronously - for n in nodes.iter().rev() { - head.rcu(|head| { - n.next.store(head.clone()); // Cloning the optional Arc - Some(Arc::clone(n)) - }); - } - // And do the checks once everyone finishes - barr.wait(); - // First, check that all our numbers are increasing by one and all are present - let mut node = head.load(); - let mut expecting = 0; - while node.is_some() { - // A bit of gymnastics, we don't have NLL yet and we need to persuade the - // borrow checker this is safe. - let next = { - let inner = node.as_ref().unwrap(); - if inner.owner == thread { - assert_eq!(expecting, inner.num); - expecting += 1; - } - inner.next.load() - }; - node = next; - } - assert_eq!(node_cnt, expecting); - // We don't want to count the ref-counts while someone still plays around with - // them and loading. - barr.wait(); - // Now that we've checked we have everything, check that all the nodes have ref - // count 2 ‒ once in the vector, once in the linked list. - for n in &nodes { - assert_eq!( - 2, - Arc::strong_count(n), - "Wrong number of counts in item {} in iteration {}", - n.num, - iter, - ); - } - // Reset the head so we don't mix the runs together, which would create a mess. - // Also, the tails might disturb the ref counts. - barr.wait(); - head.store(None); - nodes.last().unwrap().next.store(None); - } - barr.wait(); - // We went through all the iterations. Dismantle the list and see that everything - // has ref count 1. - head.store(None); - for n in &nodes { - n.next.store(None); - } - barr.wait(); // Wait until everyone resets their own nexts - for n in &nodes { - assert_eq!(1, Arc::strong_count(n)); - } - }); - } - - drop(barr); - }) - .unwrap(); -} - -struct LLNodeCnt<'a> { - next: Option>>, - num: usize, - owner: usize, - live_cnt: &'a AtomicUsize, -} - -impl<'a> Drop for LLNodeCnt<'a> { - fn drop(&mut self) { - self.live_cnt.fetch_sub(1, Ordering::Relaxed); - } -} - -/// Test where we build and then deconstruct a linked list using multiple threads. -fn storm_unroll(node_cnt: usize, iters: usize) -where - S: Default + Send + Sync, - for<'a> S: CaS>>>, -{ - let _lock = lock(); - - #[cfg(not(miri))] - let cpus = num_cpus::get(); - #[cfg(miri)] - let cpus = 2; - let barr = Barrier::new(PanicMode::Poison); - let global_cnt = AtomicUsize::new(0); - // We plan to create this many nodes during the whole test. - let live_cnt = AtomicUsize::new(cpus * node_cnt * iters); - let head = ArcSwapAny::<_, S>::from(None); - thread::scope(|scope| { - for thread in 0..cpus { - // Borrow these instead of moving. - let head = &head; - let mut barr = barr.clone(); - let global_cnt = &global_cnt; - let live_cnt = &live_cnt; - scope.spawn(move |_| { - for iter in 0..iters { - barr.wait(); - // Create bunch of nodes and put them into the list. - for i in 0..node_cnt { - let mut node = Arc::new(LLNodeCnt { - next: None, - num: i, - owner: thread, - live_cnt, - }); - head.rcu(|head| { - // Clone Option - Arc::get_mut(&mut node).unwrap().next = head.clone(); - Arc::clone(&node) - }); - } - if barr.wait().is_leader() { - let mut cnt = 0; - let mut node = head.load_full(); - while let Some(n) = node.as_ref() { - cnt += 1; - node = n.next.clone(); - } - assert_eq!(cnt, node_cnt * cpus); - } - barr.wait(); - // Keep removing items, count how many there are and that they increase in each - // thread's list. - let mut last_seen = vec![node_cnt; cpus]; - let mut cnt = 0; - while let Some(node) = - head.rcu(|head| head.as_ref().and_then(|h| h.next.clone())) - { - assert!(last_seen[node.owner] > node.num); - last_seen[node.owner] = node.num; - cnt += 1; - } - global_cnt.fetch_add(cnt, Ordering::Relaxed); - if barr.wait().is_leader() { - assert_eq!(node_cnt * cpus, global_cnt.swap(0, Ordering::Relaxed)); - } - assert_eq!( - (iters - iter - 1) * node_cnt * cpus, - live_cnt.load(Ordering::Relaxed), - ); - } - }); - } - - drop(barr); - }) - .unwrap(); - // Everything got destroyed properly. - assert_eq!(0, live_cnt.load(Ordering::Relaxed)); -} - -fn load_parallel(iters: usize) -where - S: Default + Strategy> + Send + Sync, -{ - let _lock = lock(); - #[cfg(not(miri))] - let cpus = num_cpus::get(); - #[cfg(miri)] - let cpus = 2; - let shared = ArcSwapAny::<_, S>::from(Arc::new(0)); - thread::scope(|scope| { - scope.spawn(|_| { - for i in 0..iters { - shared.store(Arc::new(i)); - } - }); - for _ in 0..cpus { - scope.spawn(|_| { - for _ in 0..iters { - let guards = (0..256).map(|_| shared.load()).collect::>(); - for (l, h) in guards.iter().tuple_windows() { - assert!(**l <= **h, "{} > {}", l, h); - } - } - }); - } - }) - .unwrap(); - let v = shared.load_full(); - assert_eq!(2, Arc::strong_count(&v)); -} - -#[cfg(not(miri))] -const ITER_SMALL: usize = 100; -#[cfg(not(miri))] -const ITER_MID: usize = 1000; - -#[cfg(miri)] -const ITER_SMALL: usize = 2; -#[cfg(miri)] -const ITER_MID: usize = 5; - -macro_rules! t { - ($name: ident, $strategy: ty) => { - mod $name { - use super::*; - - #[allow(deprecated)] // We use some "deprecated" testing strategies - type Strategy = $strategy; - - #[test] - fn storm_link_list_small() { - storm_link_list::(ITER_SMALL, 5); - } - - #[test] - #[ignore] - fn storm_link_list_large() { - storm_link_list::(10_000, 50); - } - - #[test] - fn storm_unroll_small() { - storm_unroll::(ITER_SMALL, 5); - } - - #[test] - #[ignore] - fn storm_unroll_large() { - storm_unroll::(10_000, 50); - } - - #[test] - fn load_parallel_small() { - load_parallel::(ITER_MID); - } - - #[test] - #[ignore] - fn load_parallel_large() { - load_parallel::(100_000); - } - } - }; -} - -t!(default, DefaultStrategy); -t!(independent, IndependentStrategy); -#[cfg(feature = "internal-test-strategies")] -t!( - full_slots, - arc_swap::strategy::test_strategies::FillFastSlots -); diff --git a/third-party/vendor/crossbeam-deque/.cargo-checksum.json b/third-party/vendor/crossbeam-deque/.cargo-checksum.json deleted file mode 100644 index 8e2dd0e7..00000000 --- a/third-party/vendor/crossbeam-deque/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"b0fe0b71bd530094d7aaf823bdfd5984fe4a2feea6fec3ae62975bcaed562d8c","Cargo.toml":"7c0f037ccc56d911f51bda22c475aa094e757baeb23e723bd2c2c02f324d117e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"86445da156ad68ea1d1f2dc49a3cef942ccc377ff56316aefe89732ded763aba","src/deque.rs":"54ef2940700056eff8f099e5efed10838cdf5c3ec1de91659ffcb19115fa3593","src/lib.rs":"b9899494f3933c041b059fd920fecb3226f5e91b06c3736b19501799289633e1","tests/fifo.rs":"3d98e0d4ca7cfddf10708b71642cf1ff05543d067ad837e48401d63cc31c0a18","tests/injector.rs":"fb054ef9fcac5f12e08b7b3451f370b96ab7589d32ef5c02e25958a473c45519","tests/lifo.rs":"57abdb3fc5920a422f785ba308b658bdc5400947532eeffb799f2395a2061549","tests/steal.rs":"cdf588cc13eeb275ef1231eb18e3245faca7a2d054fa6527bfdba2a34bc8f7bf"},"package":"613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"} \ No newline at end of file diff --git a/third-party/vendor/crossbeam-deque/CHANGELOG.md b/third-party/vendor/crossbeam-deque/CHANGELOG.md deleted file mode 100644 index 691d3526..00000000 --- a/third-party/vendor/crossbeam-deque/CHANGELOG.md +++ /dev/null @@ -1,137 +0,0 @@ -# Version 0.8.5 - -- Remove dependency on `cfg-if`. (#1072) - -# Version 0.8.4 - -- Bump the minimum supported Rust version to 1.61. (#1037) - -# Version 0.8.3 - -- Add `Stealer::{steal_batch_with_limit, steal_batch_with_limit_and_pop}` methods. (#903) -- Add `Injector::{steal_batch_with_limit, steal_batch_with_limit_and_pop}` methods. (#903) - -# Version 0.8.2 - -- Bump the minimum supported Rust version to 1.38. (#877) - -# Version 0.8.1 - -- Fix deque steal race condition. (#726) -- Add `Stealer::len` method. (#708) - -# Version 0.8.0 - -**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. - -- Bump the minimum supported Rust version to 1.36. -- Add `Worker::len()` and `Injector::len()` methods. -- Add `std` (enabled by default) feature for forward compatibility. - -# Version 0.7.4 - -- Fix deque steal race condition. - -# Version 0.7.3 - -**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. - -- Stop stealing from the same deque. (#448) -- Fix unsoundness issues by adopting `MaybeUninit`. (#458) - -# Version 0.7.2 - -**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. - -- Bump `crossbeam-epoch` to `0.8`. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.7.1 - -**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. - -- Bump the minimum required version of `crossbeam-utils`. - -# Version 0.7.0 - -**Note:** This release has been yanked. See [GHSA-pqqp-xmhj-wgcw](https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-pqqp-xmhj-wgcw) for details. - -- Make `Worker::pop()` faster in the FIFO case. -- Replace `fifo()` nad `lifo()` with `Worker::new_fifo()` and `Worker::new_lifo()`. -- Add more batched steal methods. -- Introduce `Injector`, a MPMC queue. -- Rename `Steal::Data` to `Steal::Success`. -- Add `Steal::or_else()` and implement `FromIterator` for `Steal`. -- Add `#[must_use]` to `Steal`. - -# Version 0.6.3 - -- Bump `crossbeam-epoch` to `0.7`. - -# Version 0.6.2 - -- Update `crosbeam-utils` to `0.6`. - -# Version 0.6.1 - -- Change a few `Relaxed` orderings to `Release` in order to fix false positives by tsan. - -# Version 0.6.0 - -- Add `Stealer::steal_many` for batched stealing. -- Change the return type of `pop` to `Pop` so that spinning can be handled manually. - -# Version 0.5.2 - -- Update `crossbeam-utils` to `0.5.0`. - -# Version 0.5.1 - -- Minor optimizations. - -# Version 0.5.0 - -- Add two deque constructors : `fifo()` and `lifo()`. -- Update `rand` to `0.5.3`. -- Rename `Deque` to `Worker`. -- Return `Option` from `Stealer::steal`. -- Remove methods `Deque::len` and `Stealer::len`. -- Remove method `Deque::stealer`. -- Remove method `Deque::steal`. - -# Version 0.4.1 - -- Update `crossbeam-epoch` to `0.5.0`. - -# Version 0.4.0 - -- Update `crossbeam-epoch` to `0.4.2`. -- Update `crossbeam-utils` to `0.4.0`. -- Require minimum Rust version 1.25. - -# Version 0.3.1 - -- Add `Deque::capacity`. -- Add `Deque::min_capacity`. -- Add `Deque::shrink_to_fit`. -- Update `crossbeam-epoch` to `0.3.0`. -- Support Rust 1.20. -- Shrink the buffer in `Deque::push` if necessary. - -# Version 0.3.0 - -- Update `crossbeam-epoch` to `0.4.0`. -- Drop support for Rust 1.13. - -# Version 0.2.0 - -- Update `crossbeam-epoch` to `0.3.0`. -- Support Rust 1.13. - -# Version 0.1.1 - -- Update `crossbeam-epoch` to `0.2.0`. - -# Version 0.1.0 - -- First implementation of the Chase-Lev deque. diff --git a/third-party/vendor/crossbeam-deque/Cargo.toml b/third-party/vendor/crossbeam-deque/Cargo.toml deleted file mode 100644 index 0fe1fed9..00000000 --- a/third-party/vendor/crossbeam-deque/Cargo.toml +++ /dev/null @@ -1,50 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.61" -name = "crossbeam-deque" -version = "0.8.5" -description = "Concurrent work-stealing deque" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque" -readme = "README.md" -keywords = [ - "chase-lev", - "lock-free", - "scheduler", - "scheduling", -] -categories = [ - "algorithms", - "concurrency", - "data-structures", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/crossbeam-rs/crossbeam" - -[dependencies.crossbeam-epoch] -version = "0.9.17" -default-features = false - -[dependencies.crossbeam-utils] -version = "0.8.18" -default-features = false - -[dev-dependencies.rand] -version = "0.8" - -[features] -default = ["std"] -std = [ - "crossbeam-epoch/std", - "crossbeam-utils/std", -] diff --git a/third-party/vendor/crossbeam-deque/LICENSE-APACHE b/third-party/vendor/crossbeam-deque/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/third-party/vendor/crossbeam-deque/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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/third-party/vendor/crossbeam-deque/LICENSE-MIT b/third-party/vendor/crossbeam-deque/LICENSE-MIT deleted file mode 100644 index 068d491f..00000000 --- a/third-party/vendor/crossbeam-deque/LICENSE-MIT +++ /dev/null @@ -1,27 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2019 The Crossbeam Project Developers - -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/third-party/vendor/crossbeam-deque/README.md b/third-party/vendor/crossbeam-deque/README.md deleted file mode 100644 index 4eae1447..00000000 --- a/third-party/vendor/crossbeam-deque/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Crossbeam Deque - -[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( -https://github.com/crossbeam-rs/crossbeam/actions) -[![License](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-deque#license) -[![Cargo](https://img.shields.io/crates/v/crossbeam-deque.svg)]( -https://crates.io/crates/crossbeam-deque) -[![Documentation](https://docs.rs/crossbeam-deque/badge.svg)]( -https://docs.rs/crossbeam-deque) -[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) - -This crate provides work-stealing deques, which are primarily intended for -building task schedulers. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam-deque = "0.8" -``` - -## Compatibility - -Crossbeam Deque supports stable Rust releases going back at least six months, -and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.61. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/third-party/vendor/crossbeam-deque/src/deque.rs b/third-party/vendor/crossbeam-deque/src/deque.rs deleted file mode 100644 index f02b03d4..00000000 --- a/third-party/vendor/crossbeam-deque/src/deque.rs +++ /dev/null @@ -1,2201 +0,0 @@ -use std::cell::{Cell, UnsafeCell}; -use std::cmp; -use std::fmt; -use std::marker::PhantomData; -use std::mem::{self, MaybeUninit}; -use std::ptr; -use std::slice; -use std::sync::atomic::{self, AtomicIsize, AtomicPtr, AtomicUsize, Ordering}; -use std::sync::Arc; - -use crossbeam_epoch::{self as epoch, Atomic, Owned}; -use crossbeam_utils::{Backoff, CachePadded}; - -// Minimum buffer capacity. -const MIN_CAP: usize = 64; -// Maximum number of tasks that can be stolen in `steal_batch()` and `steal_batch_and_pop()`. -const MAX_BATCH: usize = 32; -// If a buffer of at least this size is retired, thread-local garbage is flushed so that it gets -// deallocated as soon as possible. -const FLUSH_THRESHOLD_BYTES: usize = 1 << 10; - -/// A buffer that holds tasks in a worker queue. -/// -/// This is just a pointer to the buffer and its length - dropping an instance of this struct will -/// *not* deallocate the buffer. -struct Buffer { - /// Pointer to the allocated memory. - ptr: *mut T, - - /// Capacity of the buffer. Always a power of two. - cap: usize, -} - -unsafe impl Send for Buffer {} - -impl Buffer { - /// Allocates a new buffer with the specified capacity. - fn alloc(cap: usize) -> Buffer { - debug_assert_eq!(cap, cap.next_power_of_two()); - - let ptr = Box::into_raw( - (0..cap) - .map(|_| MaybeUninit::::uninit()) - .collect::>(), - ) - .cast::(); - - Buffer { ptr, cap } - } - - /// Deallocates the buffer. - unsafe fn dealloc(self) { - drop(Box::from_raw(slice::from_raw_parts_mut( - self.ptr.cast::>(), - self.cap, - ))); - } - - /// Returns a pointer to the task at the specified `index`. - unsafe fn at(&self, index: isize) -> *mut T { - // `self.cap` is always a power of two. - // We do all the loads at `MaybeUninit` because we might realize, after loading, that we - // don't actually have the right to access this memory. - self.ptr.offset(index & (self.cap - 1) as isize) - } - - /// Writes `task` into the specified `index`. - /// - /// This method might be concurrently called with another `read` at the same index, which is - /// technically speaking a data race and therefore UB. We should use an atomic store here, but - /// that would be more expensive and difficult to implement generically for all types `T`. - /// Hence, as a hack, we use a volatile write instead. - unsafe fn write(&self, index: isize, task: MaybeUninit) { - ptr::write_volatile(self.at(index).cast::>(), task) - } - - /// Reads a task from the specified `index`. - /// - /// This method might be concurrently called with another `write` at the same index, which is - /// technically speaking a data race and therefore UB. We should use an atomic load here, but - /// that would be more expensive and difficult to implement generically for all types `T`. - /// Hence, as a hack, we use a volatile load instead. - unsafe fn read(&self, index: isize) -> MaybeUninit { - ptr::read_volatile(self.at(index).cast::>()) - } -} - -impl Clone for Buffer { - fn clone(&self) -> Buffer { - *self - } -} - -impl Copy for Buffer {} - -/// Internal queue data shared between the worker and stealers. -/// -/// The implementation is based on the following work: -/// -/// 1. [Chase and Lev. Dynamic circular work-stealing deque. SPAA 2005.][chase-lev] -/// 2. [Le, Pop, Cohen, and Nardelli. Correct and efficient work-stealing for weak memory models. -/// PPoPP 2013.][weak-mem] -/// 3. [Norris and Demsky. CDSchecker: checking concurrent data structures written with C/C++ -/// atomics. OOPSLA 2013.][checker] -/// -/// [chase-lev]: https://dl.acm.org/citation.cfm?id=1073974 -/// [weak-mem]: https://dl.acm.org/citation.cfm?id=2442524 -/// [checker]: https://dl.acm.org/citation.cfm?id=2509514 -struct Inner { - /// The front index. - front: AtomicIsize, - - /// The back index. - back: AtomicIsize, - - /// The underlying buffer. - buffer: CachePadded>>, -} - -impl Drop for Inner { - fn drop(&mut self) { - // Load the back index, front index, and buffer. - let b = *self.back.get_mut(); - let f = *self.front.get_mut(); - - unsafe { - let buffer = self.buffer.load(Ordering::Relaxed, epoch::unprotected()); - - // Go through the buffer from front to back and drop all tasks in the queue. - let mut i = f; - while i != b { - buffer.deref().at(i).drop_in_place(); - i = i.wrapping_add(1); - } - - // Free the memory allocated by the buffer. - buffer.into_owned().into_box().dealloc(); - } - } -} - -/// Worker queue flavor: FIFO or LIFO. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -enum Flavor { - /// The first-in first-out flavor. - Fifo, - - /// The last-in first-out flavor. - Lifo, -} - -/// A worker queue. -/// -/// This is a FIFO or LIFO queue that is owned by a single thread, but other threads may steal -/// tasks from it. Task schedulers typically create a single worker queue per thread. -/// -/// # Examples -/// -/// A FIFO worker: -/// -/// ``` -/// use crossbeam_deque::{Steal, Worker}; -/// -/// let w = Worker::new_fifo(); -/// let s = w.stealer(); -/// -/// w.push(1); -/// w.push(2); -/// w.push(3); -/// -/// assert_eq!(s.steal(), Steal::Success(1)); -/// assert_eq!(w.pop(), Some(2)); -/// assert_eq!(w.pop(), Some(3)); -/// ``` -/// -/// A LIFO worker: -/// -/// ``` -/// use crossbeam_deque::{Steal, Worker}; -/// -/// let w = Worker::new_lifo(); -/// let s = w.stealer(); -/// -/// w.push(1); -/// w.push(2); -/// w.push(3); -/// -/// assert_eq!(s.steal(), Steal::Success(1)); -/// assert_eq!(w.pop(), Some(3)); -/// assert_eq!(w.pop(), Some(2)); -/// ``` -pub struct Worker { - /// A reference to the inner representation of the queue. - inner: Arc>>, - - /// A copy of `inner.buffer` for quick access. - buffer: Cell>, - - /// The flavor of the queue. - flavor: Flavor, - - /// Indicates that the worker cannot be shared among threads. - _marker: PhantomData<*mut ()>, // !Send + !Sync -} - -unsafe impl Send for Worker {} - -impl Worker { - /// Creates a FIFO worker queue. - /// - /// Tasks are pushed and popped from opposite ends. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::::new_fifo(); - /// ``` - pub fn new_fifo() -> Worker { - let buffer = Buffer::alloc(MIN_CAP); - - let inner = Arc::new(CachePadded::new(Inner { - front: AtomicIsize::new(0), - back: AtomicIsize::new(0), - buffer: CachePadded::new(Atomic::new(buffer)), - })); - - Worker { - inner, - buffer: Cell::new(buffer), - flavor: Flavor::Fifo, - _marker: PhantomData, - } - } - - /// Creates a LIFO worker queue. - /// - /// Tasks are pushed and popped from the same end. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::::new_lifo(); - /// ``` - pub fn new_lifo() -> Worker { - let buffer = Buffer::alloc(MIN_CAP); - - let inner = Arc::new(CachePadded::new(Inner { - front: AtomicIsize::new(0), - back: AtomicIsize::new(0), - buffer: CachePadded::new(Atomic::new(buffer)), - })); - - Worker { - inner, - buffer: Cell::new(buffer), - flavor: Flavor::Lifo, - _marker: PhantomData, - } - } - - /// Creates a stealer for this queue. - /// - /// The returned stealer can be shared among threads and cloned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::::new_lifo(); - /// let s = w.stealer(); - /// ``` - pub fn stealer(&self) -> Stealer { - Stealer { - inner: self.inner.clone(), - flavor: self.flavor, - } - } - - /// Resizes the internal buffer to the new capacity of `new_cap`. - #[cold] - unsafe fn resize(&self, new_cap: usize) { - // Load the back index, front index, and buffer. - let b = self.inner.back.load(Ordering::Relaxed); - let f = self.inner.front.load(Ordering::Relaxed); - let buffer = self.buffer.get(); - - // Allocate a new buffer and copy data from the old buffer to the new one. - let new = Buffer::alloc(new_cap); - let mut i = f; - while i != b { - ptr::copy_nonoverlapping(buffer.at(i), new.at(i), 1); - i = i.wrapping_add(1); - } - - let guard = &epoch::pin(); - - // Replace the old buffer with the new one. - self.buffer.replace(new); - let old = - self.inner - .buffer - .swap(Owned::new(new).into_shared(guard), Ordering::Release, guard); - - // Destroy the old buffer later. - guard.defer_unchecked(move || old.into_owned().into_box().dealloc()); - - // If the buffer is very large, then flush the thread-local garbage in order to deallocate - // it as soon as possible. - if mem::size_of::() * new_cap >= FLUSH_THRESHOLD_BYTES { - guard.flush(); - } - } - - /// Reserves enough capacity so that `reserve_cap` tasks can be pushed without growing the - /// buffer. - fn reserve(&self, reserve_cap: usize) { - if reserve_cap > 0 { - // Compute the current length. - let b = self.inner.back.load(Ordering::Relaxed); - let f = self.inner.front.load(Ordering::SeqCst); - let len = b.wrapping_sub(f) as usize; - - // The current capacity. - let cap = self.buffer.get().cap; - - // Is there enough capacity to push `reserve_cap` tasks? - if cap - len < reserve_cap { - // Keep doubling the capacity as much as is needed. - let mut new_cap = cap * 2; - while new_cap - len < reserve_cap { - new_cap *= 2; - } - - // Resize the buffer. - unsafe { - self.resize(new_cap); - } - } - } - } - - /// Returns `true` if the queue is empty. - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::new_lifo(); - /// - /// assert!(w.is_empty()); - /// w.push(1); - /// assert!(!w.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let b = self.inner.back.load(Ordering::Relaxed); - let f = self.inner.front.load(Ordering::SeqCst); - b.wrapping_sub(f) <= 0 - } - - /// Returns the number of tasks in the deque. - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::new_lifo(); - /// - /// assert_eq!(w.len(), 0); - /// w.push(1); - /// assert_eq!(w.len(), 1); - /// w.push(1); - /// assert_eq!(w.len(), 2); - /// ``` - pub fn len(&self) -> usize { - let b = self.inner.back.load(Ordering::Relaxed); - let f = self.inner.front.load(Ordering::SeqCst); - b.wrapping_sub(f).max(0) as usize - } - - /// Pushes a task into the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::new_lifo(); - /// w.push(1); - /// w.push(2); - /// ``` - pub fn push(&self, task: T) { - // Load the back index, front index, and buffer. - let b = self.inner.back.load(Ordering::Relaxed); - let f = self.inner.front.load(Ordering::Acquire); - let mut buffer = self.buffer.get(); - - // Calculate the length of the queue. - let len = b.wrapping_sub(f); - - // Is the queue full? - if len >= buffer.cap as isize { - // Yes. Grow the underlying buffer. - unsafe { - self.resize(2 * buffer.cap); - } - buffer = self.buffer.get(); - } - - // Write `task` into the slot. - unsafe { - buffer.write(b, MaybeUninit::new(task)); - } - - atomic::fence(Ordering::Release); - - // Increment the back index. - // - // This ordering could be `Relaxed`, but then thread sanitizer would falsely report data - // races because it doesn't understand fences. - self.inner.back.store(b.wrapping_add(1), Ordering::Release); - } - - /// Pops a task from the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::new_fifo(); - /// w.push(1); - /// w.push(2); - /// - /// assert_eq!(w.pop(), Some(1)); - /// assert_eq!(w.pop(), Some(2)); - /// assert_eq!(w.pop(), None); - /// ``` - pub fn pop(&self) -> Option { - // Load the back and front index. - let b = self.inner.back.load(Ordering::Relaxed); - let f = self.inner.front.load(Ordering::Relaxed); - - // Calculate the length of the queue. - let len = b.wrapping_sub(f); - - // Is the queue empty? - if len <= 0 { - return None; - } - - match self.flavor { - // Pop from the front of the queue. - Flavor::Fifo => { - // Try incrementing the front index to pop the task. - let f = self.inner.front.fetch_add(1, Ordering::SeqCst); - let new_f = f.wrapping_add(1); - - if b.wrapping_sub(new_f) < 0 { - self.inner.front.store(f, Ordering::Relaxed); - return None; - } - - unsafe { - // Read the popped task. - let buffer = self.buffer.get(); - let task = buffer.read(f).assume_init(); - - // Shrink the buffer if `len - 1` is less than one fourth of the capacity. - if buffer.cap > MIN_CAP && len <= buffer.cap as isize / 4 { - self.resize(buffer.cap / 2); - } - - Some(task) - } - } - - // Pop from the back of the queue. - Flavor::Lifo => { - // Decrement the back index. - let b = b.wrapping_sub(1); - self.inner.back.store(b, Ordering::Relaxed); - - atomic::fence(Ordering::SeqCst); - - // Load the front index. - let f = self.inner.front.load(Ordering::Relaxed); - - // Compute the length after the back index was decremented. - let len = b.wrapping_sub(f); - - if len < 0 { - // The queue is empty. Restore the back index to the original task. - self.inner.back.store(b.wrapping_add(1), Ordering::Relaxed); - None - } else { - // Read the task to be popped. - let buffer = self.buffer.get(); - let mut task = unsafe { Some(buffer.read(b)) }; - - // Are we popping the last task from the queue? - if len == 0 { - // Try incrementing the front index. - if self - .inner - .front - .compare_exchange( - f, - f.wrapping_add(1), - Ordering::SeqCst, - Ordering::Relaxed, - ) - .is_err() - { - // Failed. We didn't pop anything. Reset to `None`. - task.take(); - } - - // Restore the back index to the original task. - self.inner.back.store(b.wrapping_add(1), Ordering::Relaxed); - } else { - // Shrink the buffer if `len` is less than one fourth of the capacity. - if buffer.cap > MIN_CAP && len < buffer.cap as isize / 4 { - unsafe { - self.resize(buffer.cap / 2); - } - } - } - - task.map(|t| unsafe { t.assume_init() }) - } - } - } - } -} - -impl fmt::Debug for Worker { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Worker { .. }") - } -} - -/// A stealer handle of a worker queue. -/// -/// Stealers can be shared among threads. -/// -/// Task schedulers typically have a single worker queue per worker thread. -/// -/// # Examples -/// -/// ``` -/// use crossbeam_deque::{Steal, Worker}; -/// -/// let w = Worker::new_lifo(); -/// w.push(1); -/// w.push(2); -/// -/// let s = w.stealer(); -/// assert_eq!(s.steal(), Steal::Success(1)); -/// assert_eq!(s.steal(), Steal::Success(2)); -/// assert_eq!(s.steal(), Steal::Empty); -/// ``` -pub struct Stealer { - /// A reference to the inner representation of the queue. - inner: Arc>>, - - /// The flavor of the queue. - flavor: Flavor, -} - -unsafe impl Send for Stealer {} -unsafe impl Sync for Stealer {} - -impl Stealer { - /// Returns `true` if the queue is empty. - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::new_lifo(); - /// let s = w.stealer(); - /// - /// assert!(s.is_empty()); - /// w.push(1); - /// assert!(!s.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let f = self.inner.front.load(Ordering::Acquire); - atomic::fence(Ordering::SeqCst); - let b = self.inner.back.load(Ordering::Acquire); - b.wrapping_sub(f) <= 0 - } - - /// Returns the number of tasks in the deque. - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w = Worker::new_lifo(); - /// let s = w.stealer(); - /// - /// assert_eq!(s.len(), 0); - /// w.push(1); - /// assert_eq!(s.len(), 1); - /// w.push(2); - /// assert_eq!(s.len(), 2); - /// ``` - pub fn len(&self) -> usize { - let f = self.inner.front.load(Ordering::Acquire); - atomic::fence(Ordering::SeqCst); - let b = self.inner.back.load(Ordering::Acquire); - b.wrapping_sub(f).max(0) as usize - } - - /// Steals a task from the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::{Steal, Worker}; - /// - /// let w = Worker::new_lifo(); - /// w.push(1); - /// w.push(2); - /// - /// let s = w.stealer(); - /// assert_eq!(s.steal(), Steal::Success(1)); - /// assert_eq!(s.steal(), Steal::Success(2)); - /// ``` - pub fn steal(&self) -> Steal { - // Load the front index. - let f = self.inner.front.load(Ordering::Acquire); - - // A SeqCst fence is needed here. - // - // If the current thread is already pinned (reentrantly), we must manually issue the - // fence. Otherwise, the following pinning will issue the fence anyway, so we don't - // have to. - if epoch::is_pinned() { - atomic::fence(Ordering::SeqCst); - } - - let guard = &epoch::pin(); - - // Load the back index. - let b = self.inner.back.load(Ordering::Acquire); - - // Is the queue empty? - if b.wrapping_sub(f) <= 0 { - return Steal::Empty; - } - - // Load the buffer and read the task at the front. - let buffer = self.inner.buffer.load(Ordering::Acquire, guard); - let task = unsafe { buffer.deref().read(f) }; - - // Try incrementing the front index to steal the task. - // If the buffer has been swapped or the increment fails, we retry. - if self.inner.buffer.load(Ordering::Acquire, guard) != buffer - || self - .inner - .front - .compare_exchange(f, f.wrapping_add(1), Ordering::SeqCst, Ordering::Relaxed) - .is_err() - { - // We didn't steal this task, forget it. - return Steal::Retry; - } - - // Return the stolen task. - Steal::Success(unsafe { task.assume_init() }) - } - - /// Steals a batch of tasks and pushes them into another worker. - /// - /// How many tasks exactly will be stolen is not specified. That said, this method will try to - /// steal around half of the tasks in the queue, but also not more than some constant limit. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w1 = Worker::new_fifo(); - /// w1.push(1); - /// w1.push(2); - /// w1.push(3); - /// w1.push(4); - /// - /// let s = w1.stealer(); - /// let w2 = Worker::new_fifo(); - /// - /// let _ = s.steal_batch(&w2); - /// assert_eq!(w2.pop(), Some(1)); - /// assert_eq!(w2.pop(), Some(2)); - /// ``` - pub fn steal_batch(&self, dest: &Worker) -> Steal<()> { - self.steal_batch_with_limit(dest, MAX_BATCH) - } - - /// Steals no more than `limit` of tasks and pushes them into another worker. - /// - /// How many tasks exactly will be stolen is not specified. That said, this method will try to - /// steal around half of the tasks in the queue, but also not more than the given limit. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Worker; - /// - /// let w1 = Worker::new_fifo(); - /// w1.push(1); - /// w1.push(2); - /// w1.push(3); - /// w1.push(4); - /// w1.push(5); - /// w1.push(6); - /// - /// let s = w1.stealer(); - /// let w2 = Worker::new_fifo(); - /// - /// let _ = s.steal_batch_with_limit(&w2, 2); - /// assert_eq!(w2.pop(), Some(1)); - /// assert_eq!(w2.pop(), Some(2)); - /// assert_eq!(w2.pop(), None); - /// - /// w1.push(7); - /// w1.push(8); - /// // Setting a large limit does not guarantee that all elements will be popped. In this case, - /// // half of the elements are currently popped, but the number of popped elements is considered - /// // an implementation detail that may be changed in the future. - /// let _ = s.steal_batch_with_limit(&w2, std::usize::MAX); - /// assert_eq!(w2.len(), 3); - /// ``` - pub fn steal_batch_with_limit(&self, dest: &Worker, limit: usize) -> Steal<()> { - assert!(limit > 0); - if Arc::ptr_eq(&self.inner, &dest.inner) { - if dest.is_empty() { - return Steal::Empty; - } else { - return Steal::Success(()); - } - } - - // Load the front index. - let mut f = self.inner.front.load(Ordering::Acquire); - - // A SeqCst fence is needed here. - // - // If the current thread is already pinned (reentrantly), we must manually issue the - // fence. Otherwise, the following pinning will issue the fence anyway, so we don't - // have to. - if epoch::is_pinned() { - atomic::fence(Ordering::SeqCst); - } - - let guard = &epoch::pin(); - - // Load the back index. - let b = self.inner.back.load(Ordering::Acquire); - - // Is the queue empty? - let len = b.wrapping_sub(f); - if len <= 0 { - return Steal::Empty; - } - - // Reserve capacity for the stolen batch. - let batch_size = cmp::min((len as usize + 1) / 2, limit); - dest.reserve(batch_size); - let mut batch_size = batch_size as isize; - - // Get the destination buffer and back index. - let dest_buffer = dest.buffer.get(); - let mut dest_b = dest.inner.back.load(Ordering::Relaxed); - - // Load the buffer. - let buffer = self.inner.buffer.load(Ordering::Acquire, guard); - - match self.flavor { - // Steal a batch of tasks from the front at once. - Flavor::Fifo => { - // Copy the batch from the source to the destination buffer. - match dest.flavor { - Flavor::Fifo => { - for i in 0..batch_size { - unsafe { - let task = buffer.deref().read(f.wrapping_add(i)); - dest_buffer.write(dest_b.wrapping_add(i), task); - } - } - } - Flavor::Lifo => { - for i in 0..batch_size { - unsafe { - let task = buffer.deref().read(f.wrapping_add(i)); - dest_buffer.write(dest_b.wrapping_add(batch_size - 1 - i), task); - } - } - } - } - - // Try incrementing the front index to steal the batch. - // If the buffer has been swapped or the increment fails, we retry. - if self.inner.buffer.load(Ordering::Acquire, guard) != buffer - || self - .inner - .front - .compare_exchange( - f, - f.wrapping_add(batch_size), - Ordering::SeqCst, - Ordering::Relaxed, - ) - .is_err() - { - return Steal::Retry; - } - - dest_b = dest_b.wrapping_add(batch_size); - } - - // Steal a batch of tasks from the front one by one. - Flavor::Lifo => { - // This loop may modify the batch_size, which triggers a clippy lint warning. - // Use a new variable to avoid the warning, and to make it clear we aren't - // modifying the loop exit condition during iteration. - let original_batch_size = batch_size; - - for i in 0..original_batch_size { - // If this is not the first steal, check whether the queue is empty. - if i > 0 { - // We've already got the current front index. Now execute the fence to - // synchronize with other threads. - atomic::fence(Ordering::SeqCst); - - // Load the back index. - let b = self.inner.back.load(Ordering::Acquire); - - // Is the queue empty? - if b.wrapping_sub(f) <= 0 { - batch_size = i; - break; - } - } - - // Read the task at the front. - let task = unsafe { buffer.deref().read(f) }; - - // Try incrementing the front index to steal the task. - // If the buffer has been swapped or the increment fails, we retry. - if self.inner.buffer.load(Ordering::Acquire, guard) != buffer - || self - .inner - .front - .compare_exchange( - f, - f.wrapping_add(1), - Ordering::SeqCst, - Ordering::Relaxed, - ) - .is_err() - { - // We didn't steal this task, forget it and break from the loop. - batch_size = i; - break; - } - - // Write the stolen task into the destination buffer. - unsafe { - dest_buffer.write(dest_b, task); - } - - // Move the source front index and the destination back index one step forward. - f = f.wrapping_add(1); - dest_b = dest_b.wrapping_add(1); - } - - // If we didn't steal anything, the operation needs to be retried. - if batch_size == 0 { - return Steal::Retry; - } - - // If stealing into a FIFO queue, stolen tasks need to be reversed. - if dest.flavor == Flavor::Fifo { - for i in 0..batch_size / 2 { - unsafe { - let i1 = dest_b.wrapping_sub(batch_size - i); - let i2 = dest_b.wrapping_sub(i + 1); - let t1 = dest_buffer.read(i1); - let t2 = dest_buffer.read(i2); - dest_buffer.write(i1, t2); - dest_buffer.write(i2, t1); - } - } - } - } - } - - atomic::fence(Ordering::Release); - - // Update the back index in the destination queue. - // - // This ordering could be `Relaxed`, but then thread sanitizer would falsely report data - // races because it doesn't understand fences. - dest.inner.back.store(dest_b, Ordering::Release); - - // Return with success. - Steal::Success(()) - } - - /// Steals a batch of tasks, pushes them into another worker, and pops a task from that worker. - /// - /// How many tasks exactly will be stolen is not specified. That said, this method will try to - /// steal around half of the tasks in the queue, but also not more than some constant limit. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::{Steal, Worker}; - /// - /// let w1 = Worker::new_fifo(); - /// w1.push(1); - /// w1.push(2); - /// w1.push(3); - /// w1.push(4); - /// - /// let s = w1.stealer(); - /// let w2 = Worker::new_fifo(); - /// - /// assert_eq!(s.steal_batch_and_pop(&w2), Steal::Success(1)); - /// assert_eq!(w2.pop(), Some(2)); - /// ``` - pub fn steal_batch_and_pop(&self, dest: &Worker) -> Steal { - self.steal_batch_with_limit_and_pop(dest, MAX_BATCH) - } - - /// Steals no more than `limit` of tasks, pushes them into another worker, and pops a task from - /// that worker. - /// - /// How many tasks exactly will be stolen is not specified. That said, this method will try to - /// steal around half of the tasks in the queue, but also not more than the given limit. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::{Steal, Worker}; - /// - /// let w1 = Worker::new_fifo(); - /// w1.push(1); - /// w1.push(2); - /// w1.push(3); - /// w1.push(4); - /// w1.push(5); - /// w1.push(6); - /// - /// let s = w1.stealer(); - /// let w2 = Worker::new_fifo(); - /// - /// assert_eq!(s.steal_batch_with_limit_and_pop(&w2, 2), Steal::Success(1)); - /// assert_eq!(w2.pop(), Some(2)); - /// assert_eq!(w2.pop(), None); - /// - /// w1.push(7); - /// w1.push(8); - /// // Setting a large limit does not guarantee that all elements will be popped. In this case, - /// // half of the elements are currently popped, but the number of popped elements is considered - /// // an implementation detail that may be changed in the future. - /// assert_eq!(s.steal_batch_with_limit_and_pop(&w2, std::usize::MAX), Steal::Success(3)); - /// assert_eq!(w2.pop(), Some(4)); - /// assert_eq!(w2.pop(), Some(5)); - /// assert_eq!(w2.pop(), None); - /// ``` - pub fn steal_batch_with_limit_and_pop(&self, dest: &Worker, limit: usize) -> Steal { - assert!(limit > 0); - if Arc::ptr_eq(&self.inner, &dest.inner) { - match dest.pop() { - None => return Steal::Empty, - Some(task) => return Steal::Success(task), - } - } - - // Load the front index. - let mut f = self.inner.front.load(Ordering::Acquire); - - // A SeqCst fence is needed here. - // - // If the current thread is already pinned (reentrantly), we must manually issue the - // fence. Otherwise, the following pinning will issue the fence anyway, so we don't - // have to. - if epoch::is_pinned() { - atomic::fence(Ordering::SeqCst); - } - - let guard = &epoch::pin(); - - // Load the back index. - let b = self.inner.back.load(Ordering::Acquire); - - // Is the queue empty? - let len = b.wrapping_sub(f); - if len <= 0 { - return Steal::Empty; - } - - // Reserve capacity for the stolen batch. - let batch_size = cmp::min((len as usize - 1) / 2, limit - 1); - dest.reserve(batch_size); - let mut batch_size = batch_size as isize; - - // Get the destination buffer and back index. - let dest_buffer = dest.buffer.get(); - let mut dest_b = dest.inner.back.load(Ordering::Relaxed); - - // Load the buffer - let buffer = self.inner.buffer.load(Ordering::Acquire, guard); - - // Read the task at the front. - let mut task = unsafe { buffer.deref().read(f) }; - - match self.flavor { - // Steal a batch of tasks from the front at once. - Flavor::Fifo => { - // Copy the batch from the source to the destination buffer. - match dest.flavor { - Flavor::Fifo => { - for i in 0..batch_size { - unsafe { - let task = buffer.deref().read(f.wrapping_add(i + 1)); - dest_buffer.write(dest_b.wrapping_add(i), task); - } - } - } - Flavor::Lifo => { - for i in 0..batch_size { - unsafe { - let task = buffer.deref().read(f.wrapping_add(i + 1)); - dest_buffer.write(dest_b.wrapping_add(batch_size - 1 - i), task); - } - } - } - } - - // Try incrementing the front index to steal the task. - // If the buffer has been swapped or the increment fails, we retry. - if self.inner.buffer.load(Ordering::Acquire, guard) != buffer - || self - .inner - .front - .compare_exchange( - f, - f.wrapping_add(batch_size + 1), - Ordering::SeqCst, - Ordering::Relaxed, - ) - .is_err() - { - // We didn't steal this task, forget it. - return Steal::Retry; - } - - dest_b = dest_b.wrapping_add(batch_size); - } - - // Steal a batch of tasks from the front one by one. - Flavor::Lifo => { - // Try incrementing the front index to steal the task. - if self - .inner - .front - .compare_exchange(f, f.wrapping_add(1), Ordering::SeqCst, Ordering::Relaxed) - .is_err() - { - // We didn't steal this task, forget it. - return Steal::Retry; - } - - // Move the front index one step forward. - f = f.wrapping_add(1); - - // Repeat the same procedure for the batch steals. - // - // This loop may modify the batch_size, which triggers a clippy lint warning. - // Use a new variable to avoid the warning, and to make it clear we aren't - // modifying the loop exit condition during iteration. - let original_batch_size = batch_size; - for i in 0..original_batch_size { - // We've already got the current front index. Now execute the fence to - // synchronize with other threads. - atomic::fence(Ordering::SeqCst); - - // Load the back index. - let b = self.inner.back.load(Ordering::Acquire); - - // Is the queue empty? - if b.wrapping_sub(f) <= 0 { - batch_size = i; - break; - } - - // Read the task at the front. - let tmp = unsafe { buffer.deref().read(f) }; - - // Try incrementing the front index to steal the task. - // If the buffer has been swapped or the increment fails, we retry. - if self.inner.buffer.load(Ordering::Acquire, guard) != buffer - || self - .inner - .front - .compare_exchange( - f, - f.wrapping_add(1), - Ordering::SeqCst, - Ordering::Relaxed, - ) - .is_err() - { - // We didn't steal this task, forget it and break from the loop. - batch_size = i; - break; - } - - // Write the previously stolen task into the destination buffer. - unsafe { - dest_buffer.write(dest_b, mem::replace(&mut task, tmp)); - } - - // Move the source front index and the destination back index one step forward. - f = f.wrapping_add(1); - dest_b = dest_b.wrapping_add(1); - } - - // If stealing into a FIFO queue, stolen tasks need to be reversed. - if dest.flavor == Flavor::Fifo { - for i in 0..batch_size / 2 { - unsafe { - let i1 = dest_b.wrapping_sub(batch_size - i); - let i2 = dest_b.wrapping_sub(i + 1); - let t1 = dest_buffer.read(i1); - let t2 = dest_buffer.read(i2); - dest_buffer.write(i1, t2); - dest_buffer.write(i2, t1); - } - } - } - } - } - - atomic::fence(Ordering::Release); - - // Update the back index in the destination queue. - // - // This ordering could be `Relaxed`, but then thread sanitizer would falsely report data - // races because it doesn't understand fences. - dest.inner.back.store(dest_b, Ordering::Release); - - // Return with success. - Steal::Success(unsafe { task.assume_init() }) - } -} - -impl Clone for Stealer { - fn clone(&self) -> Stealer { - Stealer { - inner: self.inner.clone(), - flavor: self.flavor, - } - } -} - -impl fmt::Debug for Stealer { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Stealer { .. }") - } -} - -// Bits indicating the state of a slot: -// * If a task has been written into the slot, `WRITE` is set. -// * If a task has been read from the slot, `READ` is set. -// * If the block is being destroyed, `DESTROY` is set. -const WRITE: usize = 1; -const READ: usize = 2; -const DESTROY: usize = 4; - -// Each block covers one "lap" of indices. -const LAP: usize = 64; -// The maximum number of values a block can hold. -const BLOCK_CAP: usize = LAP - 1; -// How many lower bits are reserved for metadata. -const SHIFT: usize = 1; -// Indicates that the block is not the last one. -const HAS_NEXT: usize = 1; - -/// A slot in a block. -struct Slot { - /// The task. - task: UnsafeCell>, - - /// The state of the slot. - state: AtomicUsize, -} - -impl Slot { - const UNINIT: Self = Self { - task: UnsafeCell::new(MaybeUninit::uninit()), - state: AtomicUsize::new(0), - }; - - /// Waits until a task is written into the slot. - fn wait_write(&self) { - let backoff = Backoff::new(); - while self.state.load(Ordering::Acquire) & WRITE == 0 { - backoff.snooze(); - } - } -} - -/// A block in a linked list. -/// -/// Each block in the list can hold up to `BLOCK_CAP` values. -struct Block { - /// The next block in the linked list. - next: AtomicPtr>, - - /// Slots for values. - slots: [Slot; BLOCK_CAP], -} - -impl Block { - /// Creates an empty block that starts at `start_index`. - fn new() -> Block { - Self { - next: AtomicPtr::new(ptr::null_mut()), - slots: [Slot::UNINIT; BLOCK_CAP], - } - } - - /// Waits until the next pointer is set. - fn wait_next(&self) -> *mut Block { - let backoff = Backoff::new(); - loop { - let next = self.next.load(Ordering::Acquire); - if !next.is_null() { - return next; - } - backoff.snooze(); - } - } - - /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. - unsafe fn destroy(this: *mut Block, count: usize) { - // It is not necessary to set the `DESTROY` bit in the last slot because that slot has - // begun destruction of the block. - for i in (0..count).rev() { - let slot = (*this).slots.get_unchecked(i); - - // Mark the `DESTROY` bit if a thread is still using the slot. - if slot.state.load(Ordering::Acquire) & READ == 0 - && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 - { - // If a thread is still using the slot, it will continue destruction of the block. - return; - } - } - - // No thread is using the block, now it is safe to destroy it. - drop(Box::from_raw(this)); - } -} - -/// A position in a queue. -struct Position { - /// The index in the queue. - index: AtomicUsize, - - /// The block in the linked list. - block: AtomicPtr>, -} - -/// An injector queue. -/// -/// This is a FIFO queue that can be shared among multiple threads. Task schedulers typically have -/// a single injector queue, which is the entry point for new tasks. -/// -/// # Examples -/// -/// ``` -/// use crossbeam_deque::{Injector, Steal}; -/// -/// let q = Injector::new(); -/// q.push(1); -/// q.push(2); -/// -/// assert_eq!(q.steal(), Steal::Success(1)); -/// assert_eq!(q.steal(), Steal::Success(2)); -/// assert_eq!(q.steal(), Steal::Empty); -/// ``` -pub struct Injector { - /// The head of the queue. - head: CachePadded>, - - /// The tail of the queue. - tail: CachePadded>, - - /// Indicates that dropping a `Injector` may drop values of type `T`. - _marker: PhantomData, -} - -unsafe impl Send for Injector {} -unsafe impl Sync for Injector {} - -impl Default for Injector { - fn default() -> Self { - let block = Box::into_raw(Box::new(Block::::new())); - Self { - head: CachePadded::new(Position { - block: AtomicPtr::new(block), - index: AtomicUsize::new(0), - }), - tail: CachePadded::new(Position { - block: AtomicPtr::new(block), - index: AtomicUsize::new(0), - }), - _marker: PhantomData, - } - } -} - -impl Injector { - /// Creates a new injector queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Injector; - /// - /// let q = Injector::::new(); - /// ``` - pub fn new() -> Injector { - Self::default() - } - - /// Pushes a task into the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Injector; - /// - /// let w = Injector::new(); - /// w.push(1); - /// w.push(2); - /// ``` - pub fn push(&self, task: T) { - let backoff = Backoff::new(); - let mut tail = self.tail.index.load(Ordering::Acquire); - let mut block = self.tail.block.load(Ordering::Acquire); - let mut next_block = None; - - loop { - // Calculate the offset of the index into the block. - let offset = (tail >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - - // If we're going to have to install the next block, allocate it in advance in order to - // make the wait for other threads as short as possible. - if offset + 1 == BLOCK_CAP && next_block.is_none() { - next_block = Some(Box::new(Block::::new())); - } - - let new_tail = tail + (1 << SHIFT); - - // Try advancing the tail forward. - match self.tail.index.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, install the next one. - if offset + 1 == BLOCK_CAP { - let next_block = Box::into_raw(next_block.unwrap()); - let next_index = new_tail.wrapping_add(1 << SHIFT); - - self.tail.block.store(next_block, Ordering::Release); - self.tail.index.store(next_index, Ordering::Release); - (*block).next.store(next_block, Ordering::Release); - } - - // Write the task into the slot. - let slot = (*block).slots.get_unchecked(offset); - slot.task.get().write(MaybeUninit::new(task)); - slot.state.fetch_or(WRITE, Ordering::Release); - - return; - }, - Err(t) => { - tail = t; - block = self.tail.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Steals a task from the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::{Injector, Steal}; - /// - /// let q = Injector::new(); - /// q.push(1); - /// q.push(2); - /// - /// assert_eq!(q.steal(), Steal::Success(1)); - /// assert_eq!(q.steal(), Steal::Success(2)); - /// assert_eq!(q.steal(), Steal::Empty); - /// ``` - pub fn steal(&self) -> Steal { - let mut head; - let mut block; - let mut offset; - - let backoff = Backoff::new(); - loop { - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - - // Calculate the offset of the index into the block. - offset = (head >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - } else { - break; - } - } - - let mut new_head = head + (1 << SHIFT); - - if new_head & HAS_NEXT == 0 { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::Relaxed); - - // If the tail equals the head, that means the queue is empty. - if head >> SHIFT == tail >> SHIFT { - return Steal::Empty; - } - - // If head and tail are not in the same block, set `HAS_NEXT` in head. - if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { - new_head |= HAS_NEXT; - } - } - - // Try moving the head index forward. - if self - .head - .index - .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire) - .is_err() - { - return Steal::Retry; - } - - unsafe { - // If we've reached the end of the block, move to the next one. - if offset + 1 == BLOCK_CAP { - let next = (*block).wait_next(); - let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); - if !(*next).next.load(Ordering::Relaxed).is_null() { - next_index |= HAS_NEXT; - } - - self.head.block.store(next, Ordering::Release); - self.head.index.store(next_index, Ordering::Release); - } - - // Read the task. - let slot = (*block).slots.get_unchecked(offset); - slot.wait_write(); - let task = slot.task.get().read().assume_init(); - - // Destroy the block if we've reached the end, or if another thread wanted to destroy - // but couldn't because we were busy reading from the slot. - if (offset + 1 == BLOCK_CAP) - || (slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0) - { - Block::destroy(block, offset); - } - - Steal::Success(task) - } - } - - /// Steals a batch of tasks and pushes them into a worker. - /// - /// How many tasks exactly will be stolen is not specified. That said, this method will try to - /// steal around half of the tasks in the queue, but also not more than some constant limit. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::{Injector, Worker}; - /// - /// let q = Injector::new(); - /// q.push(1); - /// q.push(2); - /// q.push(3); - /// q.push(4); - /// - /// let w = Worker::new_fifo(); - /// let _ = q.steal_batch(&w); - /// assert_eq!(w.pop(), Some(1)); - /// assert_eq!(w.pop(), Some(2)); - /// ``` - pub fn steal_batch(&self, dest: &Worker) -> Steal<()> { - self.steal_batch_with_limit(dest, MAX_BATCH) - } - - /// Steals no more than of tasks and pushes them into a worker. - /// - /// How many tasks exactly will be stolen is not specified. That said, this method will try to - /// steal around half of the tasks in the queue, but also not more than some constant limit. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::{Injector, Worker}; - /// - /// let q = Injector::new(); - /// q.push(1); - /// q.push(2); - /// q.push(3); - /// q.push(4); - /// q.push(5); - /// q.push(6); - /// - /// let w = Worker::new_fifo(); - /// let _ = q.steal_batch_with_limit(&w, 2); - /// assert_eq!(w.pop(), Some(1)); - /// assert_eq!(w.pop(), Some(2)); - /// assert_eq!(w.pop(), None); - /// - /// q.push(7); - /// q.push(8); - /// // Setting a large limit does not guarantee that all elements will be popped. In this case, - /// // half of the elements are currently popped, but the number of popped elements is considered - /// // an implementation detail that may be changed in the future. - /// let _ = q.steal_batch_with_limit(&w, std::usize::MAX); - /// assert_eq!(w.len(), 3); - /// ``` - pub fn steal_batch_with_limit(&self, dest: &Worker, limit: usize) -> Steal<()> { - assert!(limit > 0); - let mut head; - let mut block; - let mut offset; - - let backoff = Backoff::new(); - loop { - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - - // Calculate the offset of the index into the block. - offset = (head >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - } else { - break; - } - } - - let mut new_head = head; - let advance; - - if new_head & HAS_NEXT == 0 { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::Relaxed); - - // If the tail equals the head, that means the queue is empty. - if head >> SHIFT == tail >> SHIFT { - return Steal::Empty; - } - - // If head and tail are not in the same block, set `HAS_NEXT` in head. Also, calculate - // the right batch size to steal. - if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { - new_head |= HAS_NEXT; - // We can steal all tasks till the end of the block. - advance = (BLOCK_CAP - offset).min(limit); - } else { - let len = (tail - head) >> SHIFT; - // Steal half of the available tasks. - advance = ((len + 1) / 2).min(limit); - } - } else { - // We can steal all tasks till the end of the block. - advance = (BLOCK_CAP - offset).min(limit); - } - - new_head += advance << SHIFT; - let new_offset = offset + advance; - - // Try moving the head index forward. - if self - .head - .index - .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire) - .is_err() - { - return Steal::Retry; - } - - // Reserve capacity for the stolen batch. - let batch_size = new_offset - offset; - dest.reserve(batch_size); - - // Get the destination buffer and back index. - let dest_buffer = dest.buffer.get(); - let dest_b = dest.inner.back.load(Ordering::Relaxed); - - unsafe { - // If we've reached the end of the block, move to the next one. - if new_offset == BLOCK_CAP { - let next = (*block).wait_next(); - let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); - if !(*next).next.load(Ordering::Relaxed).is_null() { - next_index |= HAS_NEXT; - } - - self.head.block.store(next, Ordering::Release); - self.head.index.store(next_index, Ordering::Release); - } - - // Copy values from the injector into the destination queue. - match dest.flavor { - Flavor::Fifo => { - for i in 0..batch_size { - // Read the task. - let slot = (*block).slots.get_unchecked(offset + i); - slot.wait_write(); - let task = slot.task.get().read(); - - // Write it into the destination queue. - dest_buffer.write(dest_b.wrapping_add(i as isize), task); - } - } - - Flavor::Lifo => { - for i in 0..batch_size { - // Read the task. - let slot = (*block).slots.get_unchecked(offset + i); - slot.wait_write(); - let task = slot.task.get().read(); - - // Write it into the destination queue. - dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task); - } - } - } - - atomic::fence(Ordering::Release); - - // Update the back index in the destination queue. - // - // This ordering could be `Relaxed`, but then thread sanitizer would falsely report - // data races because it doesn't understand fences. - dest.inner - .back - .store(dest_b.wrapping_add(batch_size as isize), Ordering::Release); - - // Destroy the block if we've reached the end, or if another thread wanted to destroy - // but couldn't because we were busy reading from the slot. - if new_offset == BLOCK_CAP { - Block::destroy(block, offset); - } else { - for i in offset..new_offset { - let slot = (*block).slots.get_unchecked(i); - - if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { - Block::destroy(block, offset); - break; - } - } - } - - Steal::Success(()) - } - } - - /// Steals a batch of tasks, pushes them into a worker, and pops a task from that worker. - /// - /// How many tasks exactly will be stolen is not specified. That said, this method will try to - /// steal around half of the tasks in the queue, but also not more than some constant limit. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::{Injector, Steal, Worker}; - /// - /// let q = Injector::new(); - /// q.push(1); - /// q.push(2); - /// q.push(3); - /// q.push(4); - /// - /// let w = Worker::new_fifo(); - /// assert_eq!(q.steal_batch_and_pop(&w), Steal::Success(1)); - /// assert_eq!(w.pop(), Some(2)); - /// ``` - pub fn steal_batch_and_pop(&self, dest: &Worker) -> Steal { - // TODO: we use `MAX_BATCH + 1` as the hard limit for Injecter as the performance is slightly - // better, but we may change it in the future to be compatible with the same method in Stealer. - self.steal_batch_with_limit_and_pop(dest, MAX_BATCH + 1) - } - - /// Steals no more than `limit` of tasks, pushes them into a worker, and pops a task from that worker. - /// - /// How many tasks exactly will be stolen is not specified. That said, this method will try to - /// steal around half of the tasks in the queue, but also not more than the given limit. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::{Injector, Steal, Worker}; - /// - /// let q = Injector::new(); - /// q.push(1); - /// q.push(2); - /// q.push(3); - /// q.push(4); - /// q.push(5); - /// q.push(6); - /// - /// let w = Worker::new_fifo(); - /// assert_eq!(q.steal_batch_with_limit_and_pop(&w, 2), Steal::Success(1)); - /// assert_eq!(w.pop(), Some(2)); - /// assert_eq!(w.pop(), None); - /// - /// q.push(7); - /// // Setting a large limit does not guarantee that all elements will be popped. In this case, - /// // half of the elements are currently popped, but the number of popped elements is considered - /// // an implementation detail that may be changed in the future. - /// assert_eq!(q.steal_batch_with_limit_and_pop(&w, std::usize::MAX), Steal::Success(3)); - /// assert_eq!(w.pop(), Some(4)); - /// assert_eq!(w.pop(), Some(5)); - /// assert_eq!(w.pop(), None); - /// ``` - pub fn steal_batch_with_limit_and_pop(&self, dest: &Worker, limit: usize) -> Steal { - assert!(limit > 0); - let mut head; - let mut block; - let mut offset; - - let backoff = Backoff::new(); - loop { - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - - // Calculate the offset of the index into the block. - offset = (head >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - } else { - break; - } - } - - let mut new_head = head; - let advance; - - if new_head & HAS_NEXT == 0 { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::Relaxed); - - // If the tail equals the head, that means the queue is empty. - if head >> SHIFT == tail >> SHIFT { - return Steal::Empty; - } - - // If head and tail are not in the same block, set `HAS_NEXT` in head. - if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { - new_head |= HAS_NEXT; - // We can steal all tasks till the end of the block. - advance = (BLOCK_CAP - offset).min(limit); - } else { - let len = (tail - head) >> SHIFT; - // Steal half of the available tasks. - advance = ((len + 1) / 2).min(limit); - } - } else { - // We can steal all tasks till the end of the block. - advance = (BLOCK_CAP - offset).min(limit); - } - - new_head += advance << SHIFT; - let new_offset = offset + advance; - - // Try moving the head index forward. - if self - .head - .index - .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire) - .is_err() - { - return Steal::Retry; - } - - // Reserve capacity for the stolen batch. - let batch_size = new_offset - offset - 1; - dest.reserve(batch_size); - - // Get the destination buffer and back index. - let dest_buffer = dest.buffer.get(); - let dest_b = dest.inner.back.load(Ordering::Relaxed); - - unsafe { - // If we've reached the end of the block, move to the next one. - if new_offset == BLOCK_CAP { - let next = (*block).wait_next(); - let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); - if !(*next).next.load(Ordering::Relaxed).is_null() { - next_index |= HAS_NEXT; - } - - self.head.block.store(next, Ordering::Release); - self.head.index.store(next_index, Ordering::Release); - } - - // Read the task. - let slot = (*block).slots.get_unchecked(offset); - slot.wait_write(); - let task = slot.task.get().read(); - - match dest.flavor { - Flavor::Fifo => { - // Copy values from the injector into the destination queue. - for i in 0..batch_size { - // Read the task. - let slot = (*block).slots.get_unchecked(offset + i + 1); - slot.wait_write(); - let task = slot.task.get().read(); - - // Write it into the destination queue. - dest_buffer.write(dest_b.wrapping_add(i as isize), task); - } - } - - Flavor::Lifo => { - // Copy values from the injector into the destination queue. - for i in 0..batch_size { - // Read the task. - let slot = (*block).slots.get_unchecked(offset + i + 1); - slot.wait_write(); - let task = slot.task.get().read(); - - // Write it into the destination queue. - dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task); - } - } - } - - atomic::fence(Ordering::Release); - - // Update the back index in the destination queue. - // - // This ordering could be `Relaxed`, but then thread sanitizer would falsely report - // data races because it doesn't understand fences. - dest.inner - .back - .store(dest_b.wrapping_add(batch_size as isize), Ordering::Release); - - // Destroy the block if we've reached the end, or if another thread wanted to destroy - // but couldn't because we were busy reading from the slot. - if new_offset == BLOCK_CAP { - Block::destroy(block, offset); - } else { - for i in offset..new_offset { - let slot = (*block).slots.get_unchecked(i); - - if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { - Block::destroy(block, offset); - break; - } - } - } - - Steal::Success(task.assume_init()) - } - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Injector; - /// - /// let q = Injector::new(); - /// - /// assert!(q.is_empty()); - /// q.push(1); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.index.load(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::SeqCst); - head >> SHIFT == tail >> SHIFT - } - - /// Returns the number of tasks in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Injector; - /// - /// let q = Injector::new(); - /// - /// assert_eq!(q.len(), 0); - /// q.push(1); - /// assert_eq!(q.len(), 1); - /// q.push(1); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail index, then load the head index. - let mut tail = self.tail.index.load(Ordering::SeqCst); - let mut head = self.head.index.load(Ordering::SeqCst); - - // If the tail index didn't change, we've got consistent indices to work with. - if self.tail.index.load(Ordering::SeqCst) == tail { - // Erase the lower bits. - tail &= !((1 << SHIFT) - 1); - head &= !((1 << SHIFT) - 1); - - // Fix up indices if they fall onto block ends. - if (tail >> SHIFT) & (LAP - 1) == LAP - 1 { - tail = tail.wrapping_add(1 << SHIFT); - } - if (head >> SHIFT) & (LAP - 1) == LAP - 1 { - head = head.wrapping_add(1 << SHIFT); - } - - // Rotate indices so that head falls into the first block. - let lap = (head >> SHIFT) / LAP; - tail = tail.wrapping_sub((lap * LAP) << SHIFT); - head = head.wrapping_sub((lap * LAP) << SHIFT); - - // Remove the lower bits. - tail >>= SHIFT; - head >>= SHIFT; - - // Return the difference minus the number of blocks between tail and head. - return tail - head - tail / LAP; - } - } - } -} - -impl Drop for Injector { - fn drop(&mut self) { - let mut head = *self.head.index.get_mut(); - let mut tail = *self.tail.index.get_mut(); - let mut block = *self.head.block.get_mut(); - - // Erase the lower bits. - head &= !((1 << SHIFT) - 1); - tail &= !((1 << SHIFT) - 1); - - unsafe { - // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks. - while head != tail { - let offset = (head >> SHIFT) % LAP; - - if offset < BLOCK_CAP { - // Drop the task in the slot. - let slot = (*block).slots.get_unchecked(offset); - (*slot.task.get()).assume_init_drop(); - } else { - // Deallocate the block and move to the next one. - let next = *(*block).next.get_mut(); - drop(Box::from_raw(block)); - block = next; - } - - head = head.wrapping_add(1 << SHIFT); - } - - // Deallocate the last remaining block. - drop(Box::from_raw(block)); - } - } -} - -impl fmt::Debug for Injector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Worker { .. }") - } -} - -/// Possible outcomes of a steal operation. -/// -/// # Examples -/// -/// There are lots of ways to chain results of steal operations together: -/// -/// ``` -/// use crossbeam_deque::Steal::{self, Empty, Retry, Success}; -/// -/// let collect = |v: Vec>| v.into_iter().collect::>(); -/// -/// assert_eq!(collect(vec![Empty, Empty, Empty]), Empty); -/// assert_eq!(collect(vec![Empty, Retry, Empty]), Retry); -/// assert_eq!(collect(vec![Retry, Success(1), Empty]), Success(1)); -/// -/// assert_eq!(collect(vec![Empty, Empty]).or_else(|| Retry), Retry); -/// assert_eq!(collect(vec![Retry, Empty]).or_else(|| Success(1)), Success(1)); -/// ``` -#[must_use] -#[derive(PartialEq, Eq, Copy, Clone)] -pub enum Steal { - /// The queue was empty at the time of stealing. - Empty, - - /// At least one task was successfully stolen. - Success(T), - - /// The steal operation needs to be retried. - Retry, -} - -impl Steal { - /// Returns `true` if the queue was empty at the time of stealing. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Steal::{Empty, Retry, Success}; - /// - /// assert!(!Success(7).is_empty()); - /// assert!(!Retry::.is_empty()); - /// - /// assert!(Empty::.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - match self { - Steal::Empty => true, - _ => false, - } - } - - /// Returns `true` if at least one task was stolen. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Steal::{Empty, Retry, Success}; - /// - /// assert!(!Empty::.is_success()); - /// assert!(!Retry::.is_success()); - /// - /// assert!(Success(7).is_success()); - /// ``` - pub fn is_success(&self) -> bool { - match self { - Steal::Success(_) => true, - _ => false, - } - } - - /// Returns `true` if the steal operation needs to be retried. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Steal::{Empty, Retry, Success}; - /// - /// assert!(!Empty::.is_retry()); - /// assert!(!Success(7).is_retry()); - /// - /// assert!(Retry::.is_retry()); - /// ``` - pub fn is_retry(&self) -> bool { - match self { - Steal::Retry => true, - _ => false, - } - } - - /// Returns the result of the operation, if successful. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Steal::{Empty, Retry, Success}; - /// - /// assert_eq!(Empty::.success(), None); - /// assert_eq!(Retry::.success(), None); - /// - /// assert_eq!(Success(7).success(), Some(7)); - /// ``` - pub fn success(self) -> Option { - match self { - Steal::Success(res) => Some(res), - _ => None, - } - } - - /// If no task was stolen, attempts another steal operation. - /// - /// Returns this steal result if it is `Success`. Otherwise, closure `f` is invoked and then: - /// - /// * If the second steal resulted in `Success`, it is returned. - /// * If both steals were unsuccessful but any resulted in `Retry`, then `Retry` is returned. - /// * If both resulted in `None`, then `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_deque::Steal::{Empty, Retry, Success}; - /// - /// assert_eq!(Success(1).or_else(|| Success(2)), Success(1)); - /// assert_eq!(Retry.or_else(|| Success(2)), Success(2)); - /// - /// assert_eq!(Retry.or_else(|| Empty), Retry::); - /// assert_eq!(Empty.or_else(|| Retry), Retry::); - /// - /// assert_eq!(Empty.or_else(|| Empty), Empty::); - /// ``` - pub fn or_else(self, f: F) -> Steal - where - F: FnOnce() -> Steal, - { - match self { - Steal::Empty => f(), - Steal::Success(_) => self, - Steal::Retry => { - if let Steal::Success(res) = f() { - Steal::Success(res) - } else { - Steal::Retry - } - } - } - } -} - -impl fmt::Debug for Steal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Steal::Empty => f.pad("Empty"), - Steal::Success(_) => f.pad("Success(..)"), - Steal::Retry => f.pad("Retry"), - } - } -} - -impl FromIterator> for Steal { - /// Consumes items until a `Success` is found and returns it. - /// - /// If no `Success` was found, but there was at least one `Retry`, then returns `Retry`. - /// Otherwise, `Empty` is returned. - fn from_iter(iter: I) -> Steal - where - I: IntoIterator>, - { - let mut retry = false; - for s in iter { - match &s { - Steal::Empty => {} - Steal::Success(_) => return s, - Steal::Retry => retry = true, - } - } - - if retry { - Steal::Retry - } else { - Steal::Empty - } - } -} diff --git a/third-party/vendor/crossbeam-deque/src/lib.rs b/third-party/vendor/crossbeam-deque/src/lib.rs deleted file mode 100644 index a5745d90..00000000 --- a/third-party/vendor/crossbeam-deque/src/lib.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! Concurrent work-stealing deques. -//! -//! These data structures are most commonly used in work-stealing schedulers. The typical setup -//! involves a number of threads, each having its own FIFO or LIFO queue (*worker*). There is also -//! one global FIFO queue (*injector*) and a list of references to *worker* queues that are able to -//! steal tasks (*stealers*). -//! -//! We spawn a new task onto the scheduler by pushing it into the *injector* queue. Each worker -//! thread waits in a loop until it finds the next task to run and then runs it. To find a task, it -//! first looks into its local *worker* queue, and then into the *injector* and *stealers*. -//! -//! # Queues -//! -//! [`Injector`] is a FIFO queue, where tasks are pushed and stolen from opposite ends. It is -//! shared among threads and is usually the entry point for new tasks. -//! -//! [`Worker`] has two constructors: -//! -//! * [`new_fifo()`] - Creates a FIFO queue, in which tasks are pushed and popped from opposite -//! ends. -//! * [`new_lifo()`] - Creates a LIFO queue, in which tasks are pushed and popped from the same -//! end. -//! -//! Each [`Worker`] is owned by a single thread and supports only push and pop operations. -//! -//! Method [`stealer()`] creates a [`Stealer`] that may be shared among threads and can only steal -//! tasks from its [`Worker`]. Tasks are stolen from the end opposite to where they get pushed. -//! -//! # Stealing -//! -//! Steal operations come in three flavors: -//! -//! 1. [`steal()`] - Steals one task. -//! 2. [`steal_batch()`] - Steals a batch of tasks and moves them into another worker. -//! 3. [`steal_batch_and_pop()`] - Steals a batch of tasks, moves them into another queue, and pops -//! one task from that worker. -//! -//! In contrast to push and pop operations, stealing can spuriously fail with [`Steal::Retry`], in -//! which case the steal operation needs to be retried. -//! -//! # Examples -//! -//! Suppose a thread in a work-stealing scheduler is idle and looking for the next task to run. To -//! find an available task, it might do the following: -//! -//! 1. Try popping one task from the local worker queue. -//! 2. Try stealing a batch of tasks from the global injector queue. -//! 3. Try stealing one task from another thread using the stealer list. -//! -//! An implementation of this work-stealing strategy: -//! -//! ``` -//! use crossbeam_deque::{Injector, Stealer, Worker}; -//! use std::iter; -//! -//! fn find_task( -//! local: &Worker, -//! global: &Injector, -//! stealers: &[Stealer], -//! ) -> Option { -//! // Pop a task from the local queue, if not empty. -//! local.pop().or_else(|| { -//! // Otherwise, we need to look for a task elsewhere. -//! iter::repeat_with(|| { -//! // Try stealing a batch of tasks from the global queue. -//! global.steal_batch_and_pop(local) -//! // Or try stealing a task from one of the other threads. -//! .or_else(|| stealers.iter().map(|s| s.steal()).collect()) -//! }) -//! // Loop while no task was stolen and any steal operation needs to be retried. -//! .find(|s| !s.is_retry()) -//! // Extract the stolen task, if there is one. -//! .and_then(|s| s.success()) -//! }) -//! } -//! ``` -//! -//! [`new_fifo()`]: Worker::new_fifo -//! [`new_lifo()`]: Worker::new_lifo -//! [`stealer()`]: Worker::stealer -//! [`steal()`]: Stealer::steal -//! [`steal_batch()`]: Stealer::steal_batch -//! [`steal_batch_and_pop()`]: Stealer::steal_batch_and_pop - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn( - missing_docs, - missing_debug_implementations, - rust_2018_idioms, - unreachable_pub -)] -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "std")] -mod deque; -#[cfg(feature = "std")] -pub use crate::deque::{Injector, Steal, Stealer, Worker}; diff --git a/third-party/vendor/crossbeam-deque/tests/fifo.rs b/third-party/vendor/crossbeam-deque/tests/fifo.rs deleted file mode 100644 index f98737b5..00000000 --- a/third-party/vendor/crossbeam-deque/tests/fifo.rs +++ /dev/null @@ -1,357 +0,0 @@ -use std::sync::atomic::Ordering::SeqCst; -use std::sync::atomic::{AtomicBool, AtomicUsize}; -use std::sync::{Arc, Mutex}; - -use crossbeam_deque::Steal::{Empty, Success}; -use crossbeam_deque::Worker; -use crossbeam_utils::thread::scope; -use rand::Rng; - -#[test] -fn smoke() { - let w = Worker::new_fifo(); - let s = w.stealer(); - assert_eq!(w.pop(), None); - assert_eq!(s.steal(), Empty); - - w.push(1); - assert_eq!(w.pop(), Some(1)); - assert_eq!(w.pop(), None); - assert_eq!(s.steal(), Empty); - - w.push(2); - assert_eq!(s.steal(), Success(2)); - assert_eq!(s.steal(), Empty); - assert_eq!(w.pop(), None); - - w.push(3); - w.push(4); - w.push(5); - assert_eq!(s.steal(), Success(3)); - assert_eq!(s.steal(), Success(4)); - assert_eq!(s.steal(), Success(5)); - assert_eq!(s.steal(), Empty); - - w.push(6); - w.push(7); - w.push(8); - w.push(9); - assert_eq!(w.pop(), Some(6)); - assert_eq!(s.steal(), Success(7)); - assert_eq!(w.pop(), Some(8)); - assert_eq!(w.pop(), Some(9)); - assert_eq!(w.pop(), None); -} - -#[test] -fn is_empty() { - let w = Worker::new_fifo(); - let s = w.stealer(); - - assert!(w.is_empty()); - w.push(1); - assert!(!w.is_empty()); - w.push(2); - assert!(!w.is_empty()); - let _ = w.pop(); - assert!(!w.is_empty()); - let _ = w.pop(); - assert!(w.is_empty()); - - assert!(s.is_empty()); - w.push(1); - assert!(!s.is_empty()); - w.push(2); - assert!(!s.is_empty()); - let _ = s.steal(); - assert!(!s.is_empty()); - let _ = s.steal(); - assert!(s.is_empty()); -} - -#[test] -fn spsc() { - #[cfg(miri)] - const STEPS: usize = 500; - #[cfg(not(miri))] - const STEPS: usize = 50_000; - - let w = Worker::new_fifo(); - let s = w.stealer(); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..STEPS { - loop { - if let Success(v) = s.steal() { - assert_eq!(i, v); - break; - } - } - } - - assert_eq!(s.steal(), Empty); - }); - - for i in 0..STEPS { - w.push(i); - } - }) - .unwrap(); -} - -#[test] -fn stampede() { - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - - let w = Worker::new_fifo(); - - for i in 0..COUNT { - w.push(Box::new(i + 1)); - } - let remaining = Arc::new(AtomicUsize::new(COUNT)); - - scope(|scope| { - for _ in 0..THREADS { - let s = w.stealer(); - let remaining = remaining.clone(); - - scope.spawn(move |_| { - let mut last = 0; - while remaining.load(SeqCst) > 0 { - if let Success(x) = s.steal() { - assert!(last < *x); - last = *x; - remaining.fetch_sub(1, SeqCst); - } - } - }); - } - - let mut last = 0; - while remaining.load(SeqCst) > 0 { - if let Some(x) = w.pop() { - assert!(last < *x); - last = *x; - remaining.fetch_sub(1, SeqCst); - } - } - }) - .unwrap(); -} - -#[test] -fn stress() { - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - - let w = Worker::new_fifo(); - let done = Arc::new(AtomicBool::new(false)); - let hits = Arc::new(AtomicUsize::new(0)); - - scope(|scope| { - for _ in 0..THREADS { - let s = w.stealer(); - let done = done.clone(); - let hits = hits.clone(); - - scope.spawn(move |_| { - let w2 = Worker::new_fifo(); - - while !done.load(SeqCst) { - if let Success(_) = s.steal() { - hits.fetch_add(1, SeqCst); - } - - let _ = s.steal_batch(&w2); - - if let Success(_) = s.steal_batch_and_pop(&w2) { - hits.fetch_add(1, SeqCst); - } - - while w2.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } - }); - } - - let mut rng = rand::thread_rng(); - let mut expected = 0; - while expected < COUNT { - if rng.gen_range(0..3) == 0 { - while w.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } else { - w.push(expected); - expected += 1; - } - } - - while hits.load(SeqCst) < COUNT { - while w.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } - done.store(true, SeqCst); - }) - .unwrap(); -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn no_starvation() { - const THREADS: usize = 8; - const COUNT: usize = 50_000; - - let w = Worker::new_fifo(); - let done = Arc::new(AtomicBool::new(false)); - let mut all_hits = Vec::new(); - - scope(|scope| { - for _ in 0..THREADS { - let s = w.stealer(); - let done = done.clone(); - let hits = Arc::new(AtomicUsize::new(0)); - all_hits.push(hits.clone()); - - scope.spawn(move |_| { - let w2 = Worker::new_fifo(); - - while !done.load(SeqCst) { - if let Success(_) = s.steal() { - hits.fetch_add(1, SeqCst); - } - - let _ = s.steal_batch(&w2); - - if let Success(_) = s.steal_batch_and_pop(&w2) { - hits.fetch_add(1, SeqCst); - } - - while w2.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } - }); - } - - let mut rng = rand::thread_rng(); - let mut my_hits = 0; - loop { - for i in 0..rng.gen_range(0..COUNT) { - if rng.gen_range(0..3) == 0 && my_hits == 0 { - while w.pop().is_some() { - my_hits += 1; - } - } else { - w.push(i); - } - } - - if my_hits > 0 && all_hits.iter().all(|h| h.load(SeqCst) > 0) { - break; - } - } - done.store(true, SeqCst); - }) - .unwrap(); -} - -#[test] -fn destructors() { - #[cfg(miri)] - const THREADS: usize = 2; - #[cfg(not(miri))] - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - #[cfg(miri)] - const STEPS: usize = 100; - #[cfg(not(miri))] - const STEPS: usize = 1000; - - struct Elem(usize, Arc>>); - - impl Drop for Elem { - fn drop(&mut self) { - self.1.lock().unwrap().push(self.0); - } - } - - let w = Worker::new_fifo(); - let dropped = Arc::new(Mutex::new(Vec::new())); - let remaining = Arc::new(AtomicUsize::new(COUNT)); - - for i in 0..COUNT { - w.push(Elem(i, dropped.clone())); - } - - scope(|scope| { - for _ in 0..THREADS { - let remaining = remaining.clone(); - let s = w.stealer(); - - scope.spawn(move |_| { - let w2 = Worker::new_fifo(); - let mut cnt = 0; - - while cnt < STEPS { - if let Success(_) = s.steal() { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - - let _ = s.steal_batch(&w2); - - if let Success(_) = s.steal_batch_and_pop(&w2) { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - - while w2.pop().is_some() { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - } - }); - } - - for _ in 0..STEPS { - if w.pop().is_some() { - remaining.fetch_sub(1, SeqCst); - } - } - }) - .unwrap(); - - let rem = remaining.load(SeqCst); - assert!(rem > 0); - - { - let mut v = dropped.lock().unwrap(); - assert_eq!(v.len(), COUNT - rem); - v.clear(); - } - - drop(w); - - { - let mut v = dropped.lock().unwrap(); - assert_eq!(v.len(), rem); - v.sort_unstable(); - for pair in v.windows(2) { - assert_eq!(pair[0] + 1, pair[1]); - } - } -} diff --git a/third-party/vendor/crossbeam-deque/tests/injector.rs b/third-party/vendor/crossbeam-deque/tests/injector.rs deleted file mode 100644 index f706a8d9..00000000 --- a/third-party/vendor/crossbeam-deque/tests/injector.rs +++ /dev/null @@ -1,375 +0,0 @@ -use std::sync::atomic::Ordering::SeqCst; -use std::sync::atomic::{AtomicBool, AtomicUsize}; -use std::sync::{Arc, Mutex}; - -use crossbeam_deque::Steal::{Empty, Success}; -use crossbeam_deque::{Injector, Worker}; -use crossbeam_utils::thread::scope; -use rand::Rng; - -#[test] -fn smoke() { - let q = Injector::new(); - assert_eq!(q.steal(), Empty); - - q.push(1); - q.push(2); - assert_eq!(q.steal(), Success(1)); - assert_eq!(q.steal(), Success(2)); - assert_eq!(q.steal(), Empty); - - q.push(3); - assert_eq!(q.steal(), Success(3)); - assert_eq!(q.steal(), Empty); -} - -#[test] -fn is_empty() { - let q = Injector::new(); - assert!(q.is_empty()); - - q.push(1); - assert!(!q.is_empty()); - q.push(2); - assert!(!q.is_empty()); - - let _ = q.steal(); - assert!(!q.is_empty()); - let _ = q.steal(); - assert!(q.is_empty()); - - q.push(3); - assert!(!q.is_empty()); - let _ = q.steal(); - assert!(q.is_empty()); -} - -#[test] -fn spsc() { - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - - let q = Injector::new(); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Success(v) = q.steal() { - assert_eq!(i, v); - break; - } - #[cfg(miri)] - std::hint::spin_loop(); - } - } - - assert_eq!(q.steal(), Empty); - }); - - for i in 0..COUNT { - q.push(i); - } - }) - .unwrap(); -} - -#[test] -fn mpmc() { - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = Injector::new(); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - } - - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - loop { - if let Success(n) = q.steal() { - v[n].fetch_add(1, SeqCst); - break; - } - #[cfg(miri)] - std::hint::spin_loop(); - } - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(SeqCst), THREADS); - } -} - -#[test] -fn stampede() { - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - - let q = Injector::new(); - - for i in 0..COUNT { - q.push(Box::new(i + 1)); - } - let remaining = Arc::new(AtomicUsize::new(COUNT)); - - scope(|scope| { - for _ in 0..THREADS { - let remaining = remaining.clone(); - let q = &q; - - scope.spawn(move |_| { - let mut last = 0; - while remaining.load(SeqCst) > 0 { - if let Success(x) = q.steal() { - assert!(last < *x); - last = *x; - remaining.fetch_sub(1, SeqCst); - } - } - }); - } - - let mut last = 0; - while remaining.load(SeqCst) > 0 { - if let Success(x) = q.steal() { - assert!(last < *x); - last = *x; - remaining.fetch_sub(1, SeqCst); - } - } - }) - .unwrap(); -} - -#[test] -fn stress() { - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - - let q = Injector::new(); - let done = Arc::new(AtomicBool::new(false)); - let hits = Arc::new(AtomicUsize::new(0)); - - scope(|scope| { - for _ in 0..THREADS { - let done = done.clone(); - let hits = hits.clone(); - let q = &q; - - scope.spawn(move |_| { - let w2 = Worker::new_fifo(); - - while !done.load(SeqCst) { - if let Success(_) = q.steal() { - hits.fetch_add(1, SeqCst); - } - - let _ = q.steal_batch(&w2); - - if let Success(_) = q.steal_batch_and_pop(&w2) { - hits.fetch_add(1, SeqCst); - } - - while w2.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } - }); - } - - let mut rng = rand::thread_rng(); - let mut expected = 0; - while expected < COUNT { - if rng.gen_range(0..3) == 0 { - while let Success(_) = q.steal() { - hits.fetch_add(1, SeqCst); - } - } else { - q.push(expected); - expected += 1; - } - } - - while hits.load(SeqCst) < COUNT { - while let Success(_) = q.steal() { - hits.fetch_add(1, SeqCst); - } - } - done.store(true, SeqCst); - }) - .unwrap(); -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn no_starvation() { - const THREADS: usize = 8; - const COUNT: usize = 50_000; - - let q = Injector::new(); - let done = Arc::new(AtomicBool::new(false)); - let mut all_hits = Vec::new(); - - scope(|scope| { - for _ in 0..THREADS { - let done = done.clone(); - let hits = Arc::new(AtomicUsize::new(0)); - all_hits.push(hits.clone()); - let q = &q; - - scope.spawn(move |_| { - let w2 = Worker::new_fifo(); - - while !done.load(SeqCst) { - if let Success(_) = q.steal() { - hits.fetch_add(1, SeqCst); - } - - let _ = q.steal_batch(&w2); - - if let Success(_) = q.steal_batch_and_pop(&w2) { - hits.fetch_add(1, SeqCst); - } - - while w2.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } - }); - } - - let mut rng = rand::thread_rng(); - let mut my_hits = 0; - loop { - for i in 0..rng.gen_range(0..COUNT) { - if rng.gen_range(0..3) == 0 && my_hits == 0 { - while let Success(_) = q.steal() { - my_hits += 1; - } - } else { - q.push(i); - } - } - - if my_hits > 0 && all_hits.iter().all(|h| h.load(SeqCst) > 0) { - break; - } - } - done.store(true, SeqCst); - }) - .unwrap(); -} - -#[test] -fn destructors() { - #[cfg(miri)] - const THREADS: usize = 2; - #[cfg(not(miri))] - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - #[cfg(miri)] - const STEPS: usize = 100; - #[cfg(not(miri))] - const STEPS: usize = 1000; - - struct Elem(usize, Arc>>); - - impl Drop for Elem { - fn drop(&mut self) { - self.1.lock().unwrap().push(self.0); - } - } - - let q = Injector::new(); - let dropped = Arc::new(Mutex::new(Vec::new())); - let remaining = Arc::new(AtomicUsize::new(COUNT)); - - for i in 0..COUNT { - q.push(Elem(i, dropped.clone())); - } - - scope(|scope| { - for _ in 0..THREADS { - let remaining = remaining.clone(); - let q = &q; - - scope.spawn(move |_| { - let w2 = Worker::new_fifo(); - let mut cnt = 0; - - while cnt < STEPS { - if let Success(_) = q.steal() { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - - let _ = q.steal_batch(&w2); - - if let Success(_) = q.steal_batch_and_pop(&w2) { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - - while w2.pop().is_some() { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - } - }); - } - - for _ in 0..STEPS { - if let Success(_) = q.steal() { - remaining.fetch_sub(1, SeqCst); - } - } - }) - .unwrap(); - - let rem = remaining.load(SeqCst); - assert!(rem > 0); - - { - let mut v = dropped.lock().unwrap(); - assert_eq!(v.len(), COUNT - rem); - v.clear(); - } - - drop(q); - - { - let mut v = dropped.lock().unwrap(); - assert_eq!(v.len(), rem); - v.sort_unstable(); - for pair in v.windows(2) { - assert_eq!(pair[0] + 1, pair[1]); - } - } -} diff --git a/third-party/vendor/crossbeam-deque/tests/lifo.rs b/third-party/vendor/crossbeam-deque/tests/lifo.rs deleted file mode 100644 index c1a65cd2..00000000 --- a/third-party/vendor/crossbeam-deque/tests/lifo.rs +++ /dev/null @@ -1,359 +0,0 @@ -use std::sync::atomic::Ordering::SeqCst; -use std::sync::atomic::{AtomicBool, AtomicUsize}; -use std::sync::{Arc, Mutex}; - -use crossbeam_deque::Steal::{Empty, Success}; -use crossbeam_deque::Worker; -use crossbeam_utils::thread::scope; -use rand::Rng; - -#[test] -fn smoke() { - let w = Worker::new_lifo(); - let s = w.stealer(); - assert_eq!(w.pop(), None); - assert_eq!(s.steal(), Empty); - - w.push(1); - assert_eq!(w.pop(), Some(1)); - assert_eq!(w.pop(), None); - assert_eq!(s.steal(), Empty); - - w.push(2); - assert_eq!(s.steal(), Success(2)); - assert_eq!(s.steal(), Empty); - assert_eq!(w.pop(), None); - - w.push(3); - w.push(4); - w.push(5); - assert_eq!(s.steal(), Success(3)); - assert_eq!(s.steal(), Success(4)); - assert_eq!(s.steal(), Success(5)); - assert_eq!(s.steal(), Empty); - - w.push(6); - w.push(7); - w.push(8); - w.push(9); - assert_eq!(w.pop(), Some(9)); - assert_eq!(s.steal(), Success(6)); - assert_eq!(w.pop(), Some(8)); - assert_eq!(w.pop(), Some(7)); - assert_eq!(w.pop(), None); -} - -#[test] -fn is_empty() { - let w = Worker::new_lifo(); - let s = w.stealer(); - - assert!(w.is_empty()); - w.push(1); - assert!(!w.is_empty()); - w.push(2); - assert!(!w.is_empty()); - let _ = w.pop(); - assert!(!w.is_empty()); - let _ = w.pop(); - assert!(w.is_empty()); - - assert!(s.is_empty()); - w.push(1); - assert!(!s.is_empty()); - w.push(2); - assert!(!s.is_empty()); - let _ = s.steal(); - assert!(!s.is_empty()); - let _ = s.steal(); - assert!(s.is_empty()); -} - -#[test] -fn spsc() { - #[cfg(miri)] - const STEPS: usize = 500; - #[cfg(not(miri))] - const STEPS: usize = 50_000; - - let w = Worker::new_lifo(); - let s = w.stealer(); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..STEPS { - loop { - if let Success(v) = s.steal() { - assert_eq!(i, v); - break; - } - #[cfg(miri)] - std::hint::spin_loop(); - } - } - - assert_eq!(s.steal(), Empty); - }); - - for i in 0..STEPS { - w.push(i); - } - }) - .unwrap(); -} - -#[test] -fn stampede() { - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - - let w = Worker::new_lifo(); - - for i in 0..COUNT { - w.push(Box::new(i + 1)); - } - let remaining = Arc::new(AtomicUsize::new(COUNT)); - - scope(|scope| { - for _ in 0..THREADS { - let s = w.stealer(); - let remaining = remaining.clone(); - - scope.spawn(move |_| { - let mut last = 0; - while remaining.load(SeqCst) > 0 { - if let Success(x) = s.steal() { - assert!(last < *x); - last = *x; - remaining.fetch_sub(1, SeqCst); - } - } - }); - } - - let mut last = COUNT + 1; - while remaining.load(SeqCst) > 0 { - if let Some(x) = w.pop() { - assert!(last > *x); - last = *x; - remaining.fetch_sub(1, SeqCst); - } - } - }) - .unwrap(); -} - -#[test] -fn stress() { - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - - let w = Worker::new_lifo(); - let done = Arc::new(AtomicBool::new(false)); - let hits = Arc::new(AtomicUsize::new(0)); - - scope(|scope| { - for _ in 0..THREADS { - let s = w.stealer(); - let done = done.clone(); - let hits = hits.clone(); - - scope.spawn(move |_| { - let w2 = Worker::new_lifo(); - - while !done.load(SeqCst) { - if let Success(_) = s.steal() { - hits.fetch_add(1, SeqCst); - } - - let _ = s.steal_batch(&w2); - - if let Success(_) = s.steal_batch_and_pop(&w2) { - hits.fetch_add(1, SeqCst); - } - - while w2.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } - }); - } - - let mut rng = rand::thread_rng(); - let mut expected = 0; - while expected < COUNT { - if rng.gen_range(0..3) == 0 { - while w.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } else { - w.push(expected); - expected += 1; - } - } - - while hits.load(SeqCst) < COUNT { - while w.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } - done.store(true, SeqCst); - }) - .unwrap(); -} - -#[cfg_attr(miri, ignore)] // Miri is too slow -#[test] -fn no_starvation() { - const THREADS: usize = 8; - const COUNT: usize = 50_000; - - let w = Worker::new_lifo(); - let done = Arc::new(AtomicBool::new(false)); - let mut all_hits = Vec::new(); - - scope(|scope| { - for _ in 0..THREADS { - let s = w.stealer(); - let done = done.clone(); - let hits = Arc::new(AtomicUsize::new(0)); - all_hits.push(hits.clone()); - - scope.spawn(move |_| { - let w2 = Worker::new_lifo(); - - while !done.load(SeqCst) { - if let Success(_) = s.steal() { - hits.fetch_add(1, SeqCst); - } - - let _ = s.steal_batch(&w2); - - if let Success(_) = s.steal_batch_and_pop(&w2) { - hits.fetch_add(1, SeqCst); - } - - while w2.pop().is_some() { - hits.fetch_add(1, SeqCst); - } - } - }); - } - - let mut rng = rand::thread_rng(); - let mut my_hits = 0; - loop { - for i in 0..rng.gen_range(0..COUNT) { - if rng.gen_range(0..3) == 0 && my_hits == 0 { - while w.pop().is_some() { - my_hits += 1; - } - } else { - w.push(i); - } - } - - if my_hits > 0 && all_hits.iter().all(|h| h.load(SeqCst) > 0) { - break; - } - } - done.store(true, SeqCst); - }) - .unwrap(); -} - -#[test] -fn destructors() { - #[cfg(miri)] - const THREADS: usize = 2; - #[cfg(not(miri))] - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 50_000; - #[cfg(miri)] - const STEPS: usize = 100; - #[cfg(not(miri))] - const STEPS: usize = 1000; - - struct Elem(usize, Arc>>); - - impl Drop for Elem { - fn drop(&mut self) { - self.1.lock().unwrap().push(self.0); - } - } - - let w = Worker::new_lifo(); - let dropped = Arc::new(Mutex::new(Vec::new())); - let remaining = Arc::new(AtomicUsize::new(COUNT)); - - for i in 0..COUNT { - w.push(Elem(i, dropped.clone())); - } - - scope(|scope| { - for _ in 0..THREADS { - let remaining = remaining.clone(); - let s = w.stealer(); - - scope.spawn(move |_| { - let w2 = Worker::new_lifo(); - let mut cnt = 0; - - while cnt < STEPS { - if let Success(_) = s.steal() { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - - let _ = s.steal_batch(&w2); - - if let Success(_) = s.steal_batch_and_pop(&w2) { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - - while w2.pop().is_some() { - cnt += 1; - remaining.fetch_sub(1, SeqCst); - } - } - }); - } - - for _ in 0..STEPS { - if w.pop().is_some() { - remaining.fetch_sub(1, SeqCst); - } - } - }) - .unwrap(); - - let rem = remaining.load(SeqCst); - assert!(rem > 0); - - { - let mut v = dropped.lock().unwrap(); - assert_eq!(v.len(), COUNT - rem); - v.clear(); - } - - drop(w); - - { - let mut v = dropped.lock().unwrap(); - assert_eq!(v.len(), rem); - v.sort_unstable(); - for pair in v.windows(2) { - assert_eq!(pair[0] + 1, pair[1]); - } - } -} diff --git a/third-party/vendor/crossbeam-deque/tests/steal.rs b/third-party/vendor/crossbeam-deque/tests/steal.rs deleted file mode 100644 index af249985..00000000 --- a/third-party/vendor/crossbeam-deque/tests/steal.rs +++ /dev/null @@ -1,212 +0,0 @@ -use crossbeam_deque::Steal::Success; -use crossbeam_deque::{Injector, Worker}; - -#[test] -fn steal_fifo() { - let w = Worker::new_fifo(); - for i in 1..=3 { - w.push(i); - } - - let s = w.stealer(); - assert_eq!(s.steal(), Success(1)); - assert_eq!(s.steal(), Success(2)); - assert_eq!(s.steal(), Success(3)); -} - -#[test] -fn steal_lifo() { - let w = Worker::new_lifo(); - for i in 1..=3 { - w.push(i); - } - - let s = w.stealer(); - assert_eq!(s.steal(), Success(1)); - assert_eq!(s.steal(), Success(2)); - assert_eq!(s.steal(), Success(3)); -} - -#[test] -fn steal_injector() { - let q = Injector::new(); - for i in 1..=3 { - q.push(i); - } - - assert_eq!(q.steal(), Success(1)); - assert_eq!(q.steal(), Success(2)); - assert_eq!(q.steal(), Success(3)); -} - -#[test] -fn steal_batch_fifo_fifo() { - let w = Worker::new_fifo(); - for i in 1..=4 { - w.push(i); - } - - let s = w.stealer(); - let w2 = Worker::new_fifo(); - - assert_eq!(s.steal_batch(&w2), Success(())); - assert_eq!(w2.pop(), Some(1)); - assert_eq!(w2.pop(), Some(2)); -} - -#[test] -fn steal_batch_lifo_lifo() { - let w = Worker::new_lifo(); - for i in 1..=4 { - w.push(i); - } - - let s = w.stealer(); - let w2 = Worker::new_lifo(); - - assert_eq!(s.steal_batch(&w2), Success(())); - assert_eq!(w2.pop(), Some(2)); - assert_eq!(w2.pop(), Some(1)); -} - -#[test] -fn steal_batch_fifo_lifo() { - let w = Worker::new_fifo(); - for i in 1..=4 { - w.push(i); - } - - let s = w.stealer(); - let w2 = Worker::new_lifo(); - - assert_eq!(s.steal_batch(&w2), Success(())); - assert_eq!(w2.pop(), Some(1)); - assert_eq!(w2.pop(), Some(2)); -} - -#[test] -fn steal_batch_lifo_fifo() { - let w = Worker::new_lifo(); - for i in 1..=4 { - w.push(i); - } - - let s = w.stealer(); - let w2 = Worker::new_fifo(); - - assert_eq!(s.steal_batch(&w2), Success(())); - assert_eq!(w2.pop(), Some(2)); - assert_eq!(w2.pop(), Some(1)); -} - -#[test] -fn steal_batch_injector_fifo() { - let q = Injector::new(); - for i in 1..=4 { - q.push(i); - } - - let w2 = Worker::new_fifo(); - assert_eq!(q.steal_batch(&w2), Success(())); - assert_eq!(w2.pop(), Some(1)); - assert_eq!(w2.pop(), Some(2)); -} - -#[test] -fn steal_batch_injector_lifo() { - let q = Injector::new(); - for i in 1..=4 { - q.push(i); - } - - let w2 = Worker::new_lifo(); - assert_eq!(q.steal_batch(&w2), Success(())); - assert_eq!(w2.pop(), Some(1)); - assert_eq!(w2.pop(), Some(2)); -} - -#[test] -fn steal_batch_and_pop_fifo_fifo() { - let w = Worker::new_fifo(); - for i in 1..=6 { - w.push(i); - } - - let s = w.stealer(); - let w2 = Worker::new_fifo(); - - assert_eq!(s.steal_batch_and_pop(&w2), Success(1)); - assert_eq!(w2.pop(), Some(2)); - assert_eq!(w2.pop(), Some(3)); -} - -#[test] -fn steal_batch_and_pop_lifo_lifo() { - let w = Worker::new_lifo(); - for i in 1..=6 { - w.push(i); - } - - let s = w.stealer(); - let w2 = Worker::new_lifo(); - - assert_eq!(s.steal_batch_and_pop(&w2), Success(3)); - assert_eq!(w2.pop(), Some(2)); - assert_eq!(w2.pop(), Some(1)); -} - -#[test] -fn steal_batch_and_pop_fifo_lifo() { - let w = Worker::new_fifo(); - for i in 1..=6 { - w.push(i); - } - - let s = w.stealer(); - let w2 = Worker::new_lifo(); - - assert_eq!(s.steal_batch_and_pop(&w2), Success(1)); - assert_eq!(w2.pop(), Some(2)); - assert_eq!(w2.pop(), Some(3)); -} - -#[test] -fn steal_batch_and_pop_lifo_fifo() { - let w = Worker::new_lifo(); - for i in 1..=6 { - w.push(i); - } - - let s = w.stealer(); - let w2 = Worker::new_fifo(); - - assert_eq!(s.steal_batch_and_pop(&w2), Success(3)); - assert_eq!(w2.pop(), Some(2)); - assert_eq!(w2.pop(), Some(1)); -} - -#[test] -fn steal_batch_and_pop_injector_fifo() { - let q = Injector::new(); - for i in 1..=6 { - q.push(i); - } - - let w2 = Worker::new_fifo(); - assert_eq!(q.steal_batch_and_pop(&w2), Success(1)); - assert_eq!(w2.pop(), Some(2)); - assert_eq!(w2.pop(), Some(3)); -} - -#[test] -fn steal_batch_and_pop_injector_lifo() { - let q = Injector::new(); - for i in 1..=6 { - q.push(i); - } - - let w2 = Worker::new_lifo(); - assert_eq!(q.steal_batch_and_pop(&w2), Success(1)); - assert_eq!(w2.pop(), Some(2)); - assert_eq!(w2.pop(), Some(3)); -} diff --git a/third-party/vendor/crossbeam-epoch/.cargo-checksum.json b/third-party/vendor/crossbeam-epoch/.cargo-checksum.json deleted file mode 100644 index 950173db..00000000 --- a/third-party/vendor/crossbeam-epoch/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"678c7c5b4e522345076d63e8f24f7ab4dc9f6b7428ca2f665e4017f7ef24a087","Cargo.lock":"fd85f51f6b4a2dabbb41d9f96775abd21d89221fa01c154afac970c539022f17","Cargo.toml":"cfbceb820c7a1519351826839decd3ff1b1ad54ef2c4dfc4d2c9f173e4726046","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"6ba897c52496a66705df72da33dea5f6e0ce5caa87c4ff073b0faf4e05516dad","benches/defer.rs":"c330b704d96b2ad1aed29f72c37a99da534adef8cb06a3976d5f93bf567abb20","benches/flush.rs":"0389ac6c473632f0e93c962f223404cc360257f6699b4ec90b9b3be16bb6d74f","benches/pin.rs":"2f649a5153745c7930efdb32a52f9dc522f7b8cf548a251c5e2c82ee25dc3fff","examples/sanitize.rs":"a39d1635fa61e643e59192d7a63becc97ff81f03c1f4e03d38cedefb1525026a","src/atomic.rs":"48b8b02d1e0235b2d87342c13c09d778fba076f79addef32294bed5b8f67b21a","src/collector.rs":"df05c7573413a8f3ac933de7cf941d24bd0ca7341f5923dcad2f811a020c49eb","src/default.rs":"8196e9a2a7a43fdd668177585ba1d4deaec2d16a8a9532f819e4d9afd64ca73d","src/deferred.rs":"092c49e65d5f0ccad8c868b9bcaf431b580c98b7efed98c3797d82d0b9d0c471","src/epoch.rs":"e6813975198df667423c7e1911f7a0f5cb3a917e56080eecd6250d9cca7af950","src/guard.rs":"8db7a20503f55e9e29fc1cf33f99522ec0a5873683ab16638e0e55c917bfc30a","src/internal.rs":"74a15b34b235ab428ffa41cb3a01930e29e3f91e35a288f8f6e0c3c2f56e63f6","src/lib.rs":"3f81f1727c3f74114fbd2f9225a4899834fc254f1444f7c7355901c8fd755494","src/sync/list.rs":"10aa4c59845ab9ff1d8bcb6f594b70bbe23c320fa7a2b125fdf85df88b9d61e2","src/sync/mod.rs":"326e32489d467e974c441120640a8338aa55da55c24b20276075ce9053997326","src/sync/once_lock.rs":"aa8f957604d1119c4fc7038a18c14a6281230e81005f31201c099acff284ad4b","src/sync/queue.rs":"d4ad500501c52a90b6624dc31196793be09bd19e9c298d5dd7b3ae37bee6b6a8","tests/loom.rs":"db772f4478966de6ec98774ca4093171dc942da635822a0d2d3257d31188cb9b"},"package":"5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"} \ No newline at end of file diff --git a/third-party/vendor/crossbeam-epoch/CHANGELOG.md b/third-party/vendor/crossbeam-epoch/CHANGELOG.md deleted file mode 100644 index d5ca3a07..00000000 --- a/third-party/vendor/crossbeam-epoch/CHANGELOG.md +++ /dev/null @@ -1,204 +0,0 @@ -# Version 0.9.18 - -- Remove dependency on `cfg-if`. (#1072) -- Remove dependency on `autocfg`. (#1071) - -# Version 0.9.17 - -- Remove dependency on `memoffset`. (#1058) - -# Version 0.9.16 - -- Bump the minimum supported Rust version to 1.61. (#1037) -- Improve support for targets without atomic CAS. (#1037) -- Remove build script. (#1037) -- Remove dependency on `scopeguard`. (#1045) -- Update `loom` dependency to 0.7. - -# Version 0.9.15 - -- Update `memoffset` to 0.9. (#981) - -# Version 0.9.14 - -- Update `memoffset` to 0.8. (#955) - -# Version 0.9.13 - -- Fix build script bug introduced in 0.9.12. (#932) - -# Version 0.9.12 - -**Note:** This release has been yanked due to regression fixed in 0.9.13. - -- Update `memoffset` to 0.7. (#926) -- Improve support for custom targets. (#922) - -# Version 0.9.11 - -- Removes the dependency on the `once_cell` crate to restore the MSRV. (#913) -- Work around [rust-lang#98302](https://github.com/rust-lang/rust/issues/98302), which causes compile error on windows-gnu when LTO is enabled. (#913) - -# Version 0.9.10 - -- Bump the minimum supported Rust version to 1.38. (#877) -- Mitigate the risk of segmentation faults in buggy downstream implementations. (#879) -- Add `{Atomic, Shared}::try_into_owned` (#701) - -# Version 0.9.9 - -- Replace lazy_static with once_cell. (#817) - -# Version 0.9.8 - -- Make `Atomic::null()` const function at 1.61+. (#797) - -# Version 0.9.7 - -- Fix Miri error when `-Zmiri-check-number-validity` is enabled. (#779) - -# Version 0.9.6 - -- Add `Atomic::fetch_update`. (#706) - -# Version 0.9.5 - -- Fix UB in `Pointable` impl of `[MaybeUninit]`. (#694) -- Support targets that do not have atomic CAS on stable Rust. (#698) -- Fix breakage with nightly feature due to rust-lang/rust#84510. (#692) - -# Version 0.9.4 - -**Note**: This release has been yanked. See [#693](https://github.com/crossbeam-rs/crossbeam/issues/693) for details. - -- Fix UB in `<[MaybeUninit] as Pointable>::init` when global allocator failed allocation. (#690) -- Bump `loom` dependency to version 0.5. (#686) - -# Version 0.9.3 - -**Note**: This release has been yanked. See [#693](https://github.com/crossbeam-rs/crossbeam/issues/693) for details. - -- Make `loom` dependency optional. (#666) - -# Version 0.9.2 - -**Note**: This release has been yanked. See [#693](https://github.com/crossbeam-rs/crossbeam/issues/693) for details. - -- Add `Atomic::compare_exchange` and `Atomic::compare_exchange_weak`. (#628) -- Deprecate `Atomic::compare_and_set` and `Atomic::compare_and_set_weak`. Use `Atomic::compare_exchange` or `Atomic::compare_exchange_weak` instead. (#628) -- Make `const_fn` dependency optional. (#611) -- Add unstable support for `loom`. (#487) - -# Version 0.9.1 - -**Note**: This release has been yanked. See [#693](https://github.com/crossbeam-rs/crossbeam/issues/693) for details. - -- Bump `memoffset` dependency to version 0.6. (#592) - -# Version 0.9.0 - -**Note**: This release has been yanked. See [#693](https://github.com/crossbeam-rs/crossbeam/issues/693) for details. - -- Bump the minimum supported Rust version to 1.36. -- Support dynamically sized types. - -# Version 0.8.2 - -- Fix bug in release (yanking 0.8.1) - -# Version 0.8.1 - -- Bump `autocfg` dependency to version 1.0. (#460) -- Reduce stall in list iteration. (#376) -- Stop stealing from the same deque. (#448) -- Fix unsoundness issues by adopting `MaybeUninit`. (#458) -- Fix use-after-free in lock-free queue. (#466) - -# Version 0.8.0 - -- Bump the minimum required version to 1.28. -- Fix breakage with nightly feature due to rust-lang/rust#65214. -- Make `Atomic::null()` const function at 1.31+. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.7.2 - -- Add `Atomic::into_owned()`. -- Update `memoffset` dependency. - -# Version 0.7.1 - -- Add `Shared::deref_mut()`. -- Add a Treiber stack to examples. - -# Version 0.7.0 - -- Remove `Guard::clone()`. -- Bump dependencies. - -# Version 0.6.1 - -- Update `crossbeam-utils` to `0.6`. - -# Version 0.6.0 - -- `defer` now requires `F: Send + 'static`. -- Bump the minimum Rust version to 1.26. -- Pinning while TLS is tearing down does not fail anymore. -- Rename `Handle` to `LocalHandle`. -- Add `defer_unchecked` and `defer_destroy`. -- Remove `Clone` impl for `LocalHandle`. - -# Version 0.5.2 - -- Update `crossbeam-utils` to `0.5`. - -# Version 0.5.1 - -- Fix compatibility with the latest Rust nightly. - -# Version 0.5.0 - -- Update `crossbeam-utils` to `0.4`. -- Specify the minimum Rust version to `1.25.0`. - -# Version 0.4.3 - -- Downgrade `crossbeam-utils` to `0.3` because it was a breaking change. - -# Version 0.4.2 - -- Expose the `Pointer` trait. -- Warn missing docs and missing debug impls. -- Update `crossbeam-utils` to `0.4`. - -# Version 0.4.1 - -- Add `Debug` impls for `Collector`, `Handle`, and `Guard`. -- Add `load_consume` to `Atomic`. -- Rename `Collector::handle` to `Collector::register`. -- Remove the `Send` implementation for `Handle` (this was a bug). Only - `Collector`s can be shared among multiple threads, while `Handle`s and - `Guard`s must stay within the thread in which they were created. - -# Version 0.4.0 - -- Update dependencies. -- Remove support for Rust 1.13. - -# Version 0.3.0 - -- Add support for Rust 1.13. -- Improve documentation for CAS. - -# Version 0.2.0 - -- Add method `Owned::into_box`. -- Fix a use-after-free bug in `Local::finalize`. -- Fix an ordering bug in `Global::push_bag`. -- Fix a bug in calculating distance between epochs. -- Remove `impl Into> for Owned`. - -# Version 0.1.0 - -- First version of the new epoch-based GC. diff --git a/third-party/vendor/crossbeam-epoch/Cargo.lock b/third-party/vendor/crossbeam-epoch/Cargo.lock deleted file mode 100644 index 3a2c6241..00000000 --- a/third-party/vendor/crossbeam-epoch/Cargo.lock +++ /dev/null @@ -1,457 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -dependencies = [ - "crossbeam-utils", - "loom", - "rand", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", - "loom", -] - -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows", -] - -[[package]] -name = "getrandom" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "loom" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e045d70ddfbc984eacfa964ded019534e8f6cbf36f6410aee0ed5cefa5a9175" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.3", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[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 = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "syn" -version = "2.0.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -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.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/third-party/vendor/crossbeam-epoch/Cargo.toml b/third-party/vendor/crossbeam-epoch/Cargo.toml deleted file mode 100644 index 0a8fc81c..00000000 --- a/third-party/vendor/crossbeam-epoch/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.61" -name = "crossbeam-epoch" -version = "0.9.18" -description = "Epoch-based garbage collection" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-epoch" -readme = "README.md" -keywords = [ - "lock-free", - "rcu", - "atomic", - "garbage", -] -categories = [ - "concurrency", - "memory-management", - "no-std", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/crossbeam-rs/crossbeam" - -[dependencies.crossbeam-utils] -version = "0.8.18" -default-features = false - -[dev-dependencies.rand] -version = "0.8" - -[features] -alloc = [] -default = ["std"] -loom = [ - "loom-crate", - "crossbeam-utils/loom", -] -nightly = ["crossbeam-utils/nightly"] -std = [ - "alloc", - "crossbeam-utils/std", -] - -[target."cfg(crossbeam_loom)".dependencies.loom-crate] -version = "0.7.1" -optional = true -package = "loom" diff --git a/third-party/vendor/crossbeam-epoch/LICENSE-APACHE b/third-party/vendor/crossbeam-epoch/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/third-party/vendor/crossbeam-epoch/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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/third-party/vendor/crossbeam-epoch/LICENSE-MIT b/third-party/vendor/crossbeam-epoch/LICENSE-MIT deleted file mode 100644 index 068d491f..00000000 --- a/third-party/vendor/crossbeam-epoch/LICENSE-MIT +++ /dev/null @@ -1,27 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2019 The Crossbeam Project Developers - -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/third-party/vendor/crossbeam-epoch/README.md b/third-party/vendor/crossbeam-epoch/README.md deleted file mode 100644 index ba74c7c7..00000000 --- a/third-party/vendor/crossbeam-epoch/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Crossbeam Epoch - -[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( -https://github.com/crossbeam-rs/crossbeam/actions) -[![License](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-epoch#license) -[![Cargo](https://img.shields.io/crates/v/crossbeam-epoch.svg)]( -https://crates.io/crates/crossbeam-epoch) -[![Documentation](https://docs.rs/crossbeam-epoch/badge.svg)]( -https://docs.rs/crossbeam-epoch) -[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) - -This crate provides epoch-based garbage collection for building concurrent data structures. - -When a thread removes an object from a concurrent data structure, other threads -may be still using pointers to it at the same time, so it cannot be destroyed -immediately. Epoch-based GC is an efficient mechanism for deferring destruction of -shared objects until no pointers to them can exist. - -Everything in this crate except the global GC can be used in `no_std` environments, provided that -`alloc` feature is enabled. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam-epoch = "0.9" -``` - -## Compatibility - -Crossbeam Epoch supports stable Rust releases going back at least six months, -and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.61. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/third-party/vendor/crossbeam-epoch/benches/defer.rs b/third-party/vendor/crossbeam-epoch/benches/defer.rs deleted file mode 100644 index 246f9079..00000000 --- a/third-party/vendor/crossbeam-epoch/benches/defer.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![feature(test)] - -extern crate test; - -use crossbeam_epoch::{self as epoch, Owned}; -use crossbeam_utils::thread::scope; -use test::Bencher; - -#[bench] -fn single_alloc_defer_free(b: &mut Bencher) { - b.iter(|| { - let guard = &epoch::pin(); - let p = Owned::new(1).into_shared(guard); - unsafe { - guard.defer_destroy(p); - } - }); -} - -#[bench] -fn single_defer(b: &mut Bencher) { - b.iter(|| { - let guard = &epoch::pin(); - guard.defer(move || ()); - }); -} - -#[bench] -fn multi_alloc_defer_free(b: &mut Bencher) { - const THREADS: usize = 16; - const STEPS: usize = 10_000; - - b.iter(|| { - scope(|s| { - for _ in 0..THREADS { - s.spawn(|_| { - for _ in 0..STEPS { - let guard = &epoch::pin(); - let p = Owned::new(1).into_shared(guard); - unsafe { - guard.defer_destroy(p); - } - } - }); - } - }) - .unwrap(); - }); -} - -#[bench] -fn multi_defer(b: &mut Bencher) { - const THREADS: usize = 16; - const STEPS: usize = 10_000; - - b.iter(|| { - scope(|s| { - for _ in 0..THREADS { - s.spawn(|_| { - for _ in 0..STEPS { - let guard = &epoch::pin(); - guard.defer(move || ()); - } - }); - } - }) - .unwrap(); - }); -} diff --git a/third-party/vendor/crossbeam-epoch/benches/flush.rs b/third-party/vendor/crossbeam-epoch/benches/flush.rs deleted file mode 100644 index 99aab19e..00000000 --- a/third-party/vendor/crossbeam-epoch/benches/flush.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![feature(test)] - -extern crate test; - -use std::sync::Barrier; - -use crossbeam_epoch as epoch; -use crossbeam_utils::thread::scope; -use test::Bencher; - -#[bench] -fn single_flush(b: &mut Bencher) { - const THREADS: usize = 16; - - let start = Barrier::new(THREADS + 1); - let end = Barrier::new(THREADS + 1); - - scope(|s| { - for _ in 0..THREADS { - s.spawn(|_| { - epoch::pin(); - start.wait(); - end.wait(); - }); - } - - start.wait(); - b.iter(|| epoch::pin().flush()); - end.wait(); - }) - .unwrap(); -} - -#[bench] -fn multi_flush(b: &mut Bencher) { - const THREADS: usize = 16; - const STEPS: usize = 10_000; - - b.iter(|| { - scope(|s| { - for _ in 0..THREADS { - s.spawn(|_| { - for _ in 0..STEPS { - let guard = &epoch::pin(); - guard.flush(); - } - }); - } - }) - .unwrap(); - }); -} diff --git a/third-party/vendor/crossbeam-epoch/benches/pin.rs b/third-party/vendor/crossbeam-epoch/benches/pin.rs deleted file mode 100644 index 8bf87e9b..00000000 --- a/third-party/vendor/crossbeam-epoch/benches/pin.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![feature(test)] - -extern crate test; - -use crossbeam_epoch as epoch; -use crossbeam_utils::thread::scope; -use test::Bencher; - -#[bench] -fn single_pin(b: &mut Bencher) { - b.iter(epoch::pin); -} - -#[bench] -fn multi_pin(b: &mut Bencher) { - const THREADS: usize = 16; - const STEPS: usize = 100_000; - - b.iter(|| { - scope(|s| { - for _ in 0..THREADS { - s.spawn(|_| { - for _ in 0..STEPS { - epoch::pin(); - } - }); - } - }) - .unwrap(); - }); -} diff --git a/third-party/vendor/crossbeam-epoch/examples/sanitize.rs b/third-party/vendor/crossbeam-epoch/examples/sanitize.rs deleted file mode 100644 index 4109c34a..00000000 --- a/third-party/vendor/crossbeam-epoch/examples/sanitize.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed}; -use std::sync::Arc; -use std::thread; -use std::time::{Duration, Instant}; - -use crossbeam_epoch::{self as epoch, Atomic, Collector, LocalHandle, Owned, Shared}; -use rand::Rng; - -fn worker(a: Arc>, handle: LocalHandle) -> usize { - let mut rng = rand::thread_rng(); - let mut sum = 0; - - if rng.gen() { - thread::sleep(Duration::from_millis(1)); - } - let timeout = Duration::from_millis(rng.gen_range(0..10)); - let now = Instant::now(); - - while now.elapsed() < timeout { - for _ in 0..100 { - let guard = &handle.pin(); - guard.flush(); - - let val = if rng.gen() { - let p = a.swap(Owned::new(AtomicUsize::new(sum)), AcqRel, guard); - unsafe { - guard.defer_destroy(p); - guard.flush(); - p.deref().load(Relaxed) - } - } else { - let p = a.load(Acquire, guard); - unsafe { p.deref().fetch_add(sum, Relaxed) } - }; - - sum = sum.wrapping_add(val); - } - } - - sum -} - -fn main() { - for _ in 0..100 { - let collector = Collector::new(); - let a = Arc::new(Atomic::new(AtomicUsize::new(777))); - - let threads = (0..16) - .map(|_| { - let a = a.clone(); - let c = collector.clone(); - thread::spawn(move || worker(a, c.register())) - }) - .collect::>(); - - for t in threads { - t.join().unwrap(); - } - - unsafe { - a.swap(Shared::null(), AcqRel, epoch::unprotected()) - .into_owned(); - } - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/atomic.rs b/third-party/vendor/crossbeam-epoch/src/atomic.rs deleted file mode 100644 index 41b4cd91..00000000 --- a/third-party/vendor/crossbeam-epoch/src/atomic.rs +++ /dev/null @@ -1,1702 +0,0 @@ -use alloc::boxed::Box; -use core::alloc::Layout; -use core::borrow::{Borrow, BorrowMut}; -use core::cmp; -use core::fmt; -use core::marker::PhantomData; -use core::mem::{self, MaybeUninit}; -use core::ops::{Deref, DerefMut}; -use core::ptr; -use core::slice; - -use crate::guard::Guard; -use crate::primitive::sync::atomic::{AtomicUsize, Ordering}; -use crossbeam_utils::atomic::AtomicConsume; - -/// Given ordering for the success case in a compare-exchange operation, returns the strongest -/// appropriate ordering for the failure case. -#[inline] -fn strongest_failure_ordering(ord: Ordering) -> Ordering { - use self::Ordering::*; - match ord { - Relaxed | Release => Relaxed, - Acquire | AcqRel => Acquire, - _ => SeqCst, - } -} - -/// The error returned on failed compare-and-set operation. -// TODO: remove in the next major version. -#[deprecated(note = "Use `CompareExchangeError` instead")] -pub type CompareAndSetError<'g, T, P> = CompareExchangeError<'g, T, P>; - -/// The error returned on failed compare-and-swap operation. -pub struct CompareExchangeError<'g, T: ?Sized + Pointable, P: Pointer> { - /// The value in the atomic pointer at the time of the failed operation. - pub current: Shared<'g, T>, - - /// The new value, which the operation failed to store. - pub new: P, -} - -impl + fmt::Debug> fmt::Debug for CompareExchangeError<'_, T, P> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("CompareExchangeError") - .field("current", &self.current) - .field("new", &self.new) - .finish() - } -} - -/// Memory orderings for compare-and-set operations. -/// -/// A compare-and-set operation can have different memory orderings depending on whether it -/// succeeds or fails. This trait generalizes different ways of specifying memory orderings. -/// -/// The two ways of specifying orderings for compare-and-set are: -/// -/// 1. Just one `Ordering` for the success case. In case of failure, the strongest appropriate -/// ordering is chosen. -/// 2. A pair of `Ordering`s. The first one is for the success case, while the second one is -/// for the failure case. -// TODO: remove in the next major version. -#[deprecated( - note = "`compare_and_set` and `compare_and_set_weak` that use this trait are deprecated, \ - use `compare_exchange` or `compare_exchange_weak instead`" -)] -pub trait CompareAndSetOrdering { - /// The ordering of the operation when it succeeds. - fn success(&self) -> Ordering; - - /// The ordering of the operation when it fails. - /// - /// The failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than - /// the success ordering. - fn failure(&self) -> Ordering; -} - -#[allow(deprecated)] -impl CompareAndSetOrdering for Ordering { - #[inline] - fn success(&self) -> Ordering { - *self - } - - #[inline] - fn failure(&self) -> Ordering { - strongest_failure_ordering(*self) - } -} - -#[allow(deprecated)] -impl CompareAndSetOrdering for (Ordering, Ordering) { - #[inline] - fn success(&self) -> Ordering { - self.0 - } - - #[inline] - fn failure(&self) -> Ordering { - self.1 - } -} - -/// Returns a bitmask containing the unused least significant bits of an aligned pointer to `T`. -#[inline] -fn low_bits() -> usize { - (1 << T::ALIGN.trailing_zeros()) - 1 -} - -/// Panics if the pointer is not properly unaligned. -#[inline] -fn ensure_aligned(raw: usize) { - assert_eq!(raw & low_bits::(), 0, "unaligned pointer"); -} - -/// Given a tagged pointer `data`, returns the same pointer, but tagged with `tag`. -/// -/// `tag` is truncated to fit into the unused bits of the pointer to `T`. -#[inline] -fn compose_tag(data: usize, tag: usize) -> usize { - (data & !low_bits::()) | (tag & low_bits::()) -} - -/// Decomposes a tagged pointer `data` into the pointer and the tag. -#[inline] -fn decompose_tag(data: usize) -> (usize, usize) { - (data & !low_bits::(), data & low_bits::()) -} - -/// Types that are pointed to by a single word. -/// -/// In concurrent programming, it is necessary to represent an object within a word because atomic -/// operations (e.g., reads, writes, read-modify-writes) support only single words. This trait -/// qualifies such types that are pointed to by a single word. -/// -/// The trait generalizes `Box` for a sized type `T`. In a box, an object of type `T` is -/// allocated in heap and it is owned by a single-word pointer. This trait is also implemented for -/// `[MaybeUninit]` by storing its size along with its elements and pointing to the pair of array -/// size and elements. -/// -/// Pointers to `Pointable` types can be stored in [`Atomic`], [`Owned`], and [`Shared`]. In -/// particular, Crossbeam supports dynamically sized slices as follows. -/// -/// ``` -/// use std::mem::MaybeUninit; -/// use crossbeam_epoch::Owned; -/// -/// let o = Owned::<[MaybeUninit]>::init(10); // allocating [i32; 10] -/// ``` -pub trait Pointable { - /// The alignment of pointer. - const ALIGN: usize; - - /// The type for initializers. - type Init; - - /// Initializes a with the given initializer. - /// - /// # Safety - /// - /// The result should be a multiple of `ALIGN`. - unsafe fn init(init: Self::Init) -> usize; - - /// Dereferences the given pointer. - /// - /// # Safety - /// - /// - The given `ptr` should have been initialized with [`Pointable::init`]. - /// - `ptr` should not have yet been dropped by [`Pointable::drop`]. - /// - `ptr` should not be mutably dereferenced by [`Pointable::deref_mut`] concurrently. - unsafe fn deref<'a>(ptr: usize) -> &'a Self; - - /// Mutably dereferences the given pointer. - /// - /// # Safety - /// - /// - The given `ptr` should have been initialized with [`Pointable::init`]. - /// - `ptr` should not have yet been dropped by [`Pointable::drop`]. - /// - `ptr` should not be dereferenced by [`Pointable::deref`] or [`Pointable::deref_mut`] - /// concurrently. - unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut Self; - - /// Drops the object pointed to by the given pointer. - /// - /// # Safety - /// - /// - The given `ptr` should have been initialized with [`Pointable::init`]. - /// - `ptr` should not have yet been dropped by [`Pointable::drop`]. - /// - `ptr` should not be dereferenced by [`Pointable::deref`] or [`Pointable::deref_mut`] - /// concurrently. - unsafe fn drop(ptr: usize); -} - -impl Pointable for T { - const ALIGN: usize = mem::align_of::(); - - type Init = T; - - unsafe fn init(init: Self::Init) -> usize { - Box::into_raw(Box::new(init)) as usize - } - - unsafe fn deref<'a>(ptr: usize) -> &'a Self { - &*(ptr as *const T) - } - - unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut Self { - &mut *(ptr as *mut T) - } - - unsafe fn drop(ptr: usize) { - drop(Box::from_raw(ptr as *mut T)); - } -} - -/// Array with size. -/// -/// # Memory layout -/// -/// An array consisting of size and elements: -/// -/// ```text -/// elements -/// | -/// | -/// ------------------------------------ -/// | size | 0 | 1 | 2 | 3 | 4 | 5 | 6 | -/// ------------------------------------ -/// ``` -/// -/// Its memory layout is different from that of `Box<[T]>` in that size is in the allocation (not -/// along with pointer as in `Box<[T]>`). -/// -/// Elements are not present in the type, but they will be in the allocation. -/// ``` -#[repr(C)] -struct Array { - /// The number of elements (not the number of bytes). - len: usize, - elements: [MaybeUninit; 0], -} - -impl Array { - fn layout(len: usize) -> Layout { - Layout::new::() - .extend(Layout::array::>(len).unwrap()) - .unwrap() - .0 - .pad_to_align() - } -} - -impl Pointable for [MaybeUninit] { - const ALIGN: usize = mem::align_of::>(); - - type Init = usize; - - unsafe fn init(len: Self::Init) -> usize { - let layout = Array::::layout(len); - let ptr = alloc::alloc::alloc(layout).cast::>(); - if ptr.is_null() { - alloc::alloc::handle_alloc_error(layout); - } - ptr::addr_of_mut!((*ptr).len).write(len); - ptr as usize - } - - unsafe fn deref<'a>(ptr: usize) -> &'a Self { - let array = &*(ptr as *const Array); - slice::from_raw_parts(array.elements.as_ptr() as *const _, array.len) - } - - unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut Self { - let array = &*(ptr as *mut Array); - slice::from_raw_parts_mut(array.elements.as_ptr() as *mut _, array.len) - } - - unsafe fn drop(ptr: usize) { - let len = (*(ptr as *mut Array)).len; - let layout = Array::::layout(len); - alloc::alloc::dealloc(ptr as *mut u8, layout); - } -} - -/// An atomic pointer that can be safely shared between threads. -/// -/// The pointer must be properly aligned. Since it is aligned, a tag can be stored into the unused -/// least significant bits of the address. For example, the tag for a pointer to a sized type `T` -/// should be less than `(1 << mem::align_of::().trailing_zeros())`. -/// -/// Any method that loads the pointer must be passed a reference to a [`Guard`]. -/// -/// Crossbeam supports dynamically sized types. See [`Pointable`] for details. -pub struct Atomic { - data: AtomicUsize, - _marker: PhantomData<*mut T>, -} - -unsafe impl Send for Atomic {} -unsafe impl Sync for Atomic {} - -impl Atomic { - /// Allocates `value` on the heap and returns a new atomic pointer pointing to it. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Atomic; - /// - /// let a = Atomic::new(1234); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn new(init: T) -> Atomic { - Self::init(init) - } -} - -impl Atomic { - /// Allocates `value` on the heap and returns a new atomic pointer pointing to it. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Atomic; - /// - /// let a = Atomic::::init(1234); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn init(init: T::Init) -> Atomic { - Self::from(Owned::init(init)) - } - - /// Returns a new atomic pointer pointing to the tagged pointer `data`. - fn from_usize(data: usize) -> Self { - Self { - data: AtomicUsize::new(data), - _marker: PhantomData, - } - } - - /// Returns a new null atomic pointer. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Atomic; - /// - /// let a = Atomic::::null(); - /// ``` - #[cfg(not(crossbeam_loom))] - pub const fn null() -> Atomic { - Self { - data: AtomicUsize::new(0), - _marker: PhantomData, - } - } - /// Returns a new null atomic pointer. - #[cfg(crossbeam_loom)] - pub fn null() -> Atomic { - Self { - data: AtomicUsize::new(0), - _marker: PhantomData, - } - } - - /// Loads a `Shared` from the atomic pointer. - /// - /// This method takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// let guard = &epoch::pin(); - /// let p = a.load(SeqCst, guard); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn load<'g>(&self, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { - unsafe { Shared::from_usize(self.data.load(ord)) } - } - - /// Loads a `Shared` from the atomic pointer using a "consume" memory ordering. - /// - /// This is similar to the "acquire" ordering, except that an ordering is - /// only guaranteed with operations that "depend on" the result of the load. - /// However consume loads are usually much faster than acquire loads on - /// architectures with a weak memory model since they don't require memory - /// fence instructions. - /// - /// The exact definition of "depend on" is a bit vague, but it works as you - /// would expect in practice since a lot of software, especially the Linux - /// kernel, rely on this behavior. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// - /// let a = Atomic::new(1234); - /// let guard = &epoch::pin(); - /// let p = a.load_consume(guard); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn load_consume<'g>(&self, _: &'g Guard) -> Shared<'g, T> { - unsafe { Shared::from_usize(self.data.load_consume()) } - } - - /// Stores a `Shared` or `Owned` pointer into the atomic pointer. - /// - /// This method takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{Atomic, Owned, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// # unsafe { drop(a.load(SeqCst, &crossbeam_epoch::pin()).into_owned()); } // avoid leak - /// a.store(Shared::null(), SeqCst); - /// a.store(Owned::new(1234), SeqCst); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn store>(&self, new: P, ord: Ordering) { - self.data.store(new.into_usize(), ord); - } - - /// Stores a `Shared` or `Owned` pointer into the atomic pointer, returning the previous - /// `Shared`. - /// - /// This method takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// let guard = &epoch::pin(); - /// let p = a.swap(Shared::null(), SeqCst, guard); - /// # unsafe { drop(p.into_owned()); } // avoid leak - /// ``` - pub fn swap<'g, P: Pointer>(&self, new: P, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { - unsafe { Shared::from_usize(self.data.swap(new.into_usize(), ord)) } - } - - /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current - /// value is the same as `current`. The tag is also taken into account, so two pointers to the - /// same object, but with different tags, will not be considered equal. - /// - /// The return value is a result indicating whether the new pointer was written. On success the - /// pointer that was written is returned. On failure the actual current value and `new` are - /// returned. - /// - /// This method takes two `Ordering` arguments to describe the memory - /// ordering of this operation. `success` describes the required ordering for the - /// read-modify-write operation that takes place if the comparison with `current` succeeds. - /// `failure` describes the required ordering for the load operation that takes place when - /// the comparison fails. Using `Acquire` as success ordering makes the store part - /// of this operation `Relaxed`, and using `Release` makes the successful load - /// `Relaxed`. The failure ordering can only be `SeqCst`, `Acquire` or `Relaxed` - /// and must be equivalent to or weaker than the success ordering. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// - /// let guard = &epoch::pin(); - /// let curr = a.load(SeqCst, guard); - /// let res1 = a.compare_exchange(curr, Shared::null(), SeqCst, SeqCst, guard); - /// let res2 = a.compare_exchange(curr, Owned::new(5678), SeqCst, SeqCst, guard); - /// # unsafe { drop(curr.into_owned()); } // avoid leak - /// ``` - pub fn compare_exchange<'g, P>( - &self, - current: Shared<'_, T>, - new: P, - success: Ordering, - failure: Ordering, - _: &'g Guard, - ) -> Result, CompareExchangeError<'g, T, P>> - where - P: Pointer, - { - let new = new.into_usize(); - self.data - .compare_exchange(current.into_usize(), new, success, failure) - .map(|_| unsafe { Shared::from_usize(new) }) - .map_err(|current| unsafe { - CompareExchangeError { - current: Shared::from_usize(current), - new: P::from_usize(new), - } - }) - } - - /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current - /// value is the same as `current`. The tag is also taken into account, so two pointers to the - /// same object, but with different tags, will not be considered equal. - /// - /// Unlike [`compare_exchange`], this method is allowed to spuriously fail even when comparison - /// succeeds, which can result in more efficient code on some platforms. The return value is a - /// result indicating whether the new pointer was written. On success the pointer that was - /// written is returned. On failure the actual current value and `new` are returned. - /// - /// This method takes two `Ordering` arguments to describe the memory - /// ordering of this operation. `success` describes the required ordering for the - /// read-modify-write operation that takes place if the comparison with `current` succeeds. - /// `failure` describes the required ordering for the load operation that takes place when - /// the comparison fails. Using `Acquire` as success ordering makes the store part - /// of this operation `Relaxed`, and using `Release` makes the successful load - /// `Relaxed`. The failure ordering can only be `SeqCst`, `Acquire` or `Relaxed` - /// and must be equivalent to or weaker than the success ordering. - /// - /// [`compare_exchange`]: Atomic::compare_exchange - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// let guard = &epoch::pin(); - /// - /// let mut new = Owned::new(5678); - /// let mut ptr = a.load(SeqCst, guard); - /// # unsafe { drop(a.load(SeqCst, guard).into_owned()); } // avoid leak - /// loop { - /// match a.compare_exchange_weak(ptr, new, SeqCst, SeqCst, guard) { - /// Ok(p) => { - /// ptr = p; - /// break; - /// } - /// Err(err) => { - /// ptr = err.current; - /// new = err.new; - /// } - /// } - /// } - /// - /// let mut curr = a.load(SeqCst, guard); - /// loop { - /// match a.compare_exchange_weak(curr, Shared::null(), SeqCst, SeqCst, guard) { - /// Ok(_) => break, - /// Err(err) => curr = err.current, - /// } - /// } - /// # unsafe { drop(curr.into_owned()); } // avoid leak - /// ``` - pub fn compare_exchange_weak<'g, P>( - &self, - current: Shared<'_, T>, - new: P, - success: Ordering, - failure: Ordering, - _: &'g Guard, - ) -> Result, CompareExchangeError<'g, T, P>> - where - P: Pointer, - { - let new = new.into_usize(); - self.data - .compare_exchange_weak(current.into_usize(), new, success, failure) - .map(|_| unsafe { Shared::from_usize(new) }) - .map_err(|current| unsafe { - CompareExchangeError { - current: Shared::from_usize(current), - new: P::from_usize(new), - } - }) - } - - /// Fetches the pointer, and then applies a function to it that returns a new value. - /// Returns a `Result` of `Ok(previous_value)` if the function returned `Some`, else `Err(_)`. - /// - /// Note that the given function may be called multiple times if the value has been changed by - /// other threads in the meantime, as long as the function returns `Some(_)`, but the function - /// will have been applied only once to the stored value. - /// - /// `fetch_update` takes two [`Ordering`] arguments to describe the memory - /// ordering of this operation. The first describes the required ordering for - /// when the operation finally succeeds while the second describes the - /// required ordering for loads. These correspond to the success and failure - /// orderings of [`Atomic::compare_exchange`] respectively. - /// - /// Using [`Acquire`] as success ordering makes the store part of this - /// operation [`Relaxed`], and using [`Release`] makes the final successful - /// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], - /// [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the - /// success ordering. - /// - /// [`Relaxed`]: Ordering::Relaxed - /// [`Acquire`]: Ordering::Acquire - /// [`Release`]: Ordering::Release - /// [`SeqCst`]: Ordering::SeqCst - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// let guard = &epoch::pin(); - /// - /// let res1 = a.fetch_update(SeqCst, SeqCst, guard, |x| Some(x.with_tag(1))); - /// assert!(res1.is_ok()); - /// - /// let res2 = a.fetch_update(SeqCst, SeqCst, guard, |x| None); - /// assert!(res2.is_err()); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn fetch_update<'g, F>( - &self, - set_order: Ordering, - fail_order: Ordering, - guard: &'g Guard, - mut func: F, - ) -> Result, Shared<'g, T>> - where - F: FnMut(Shared<'g, T>) -> Option>, - { - let mut prev = self.load(fail_order, guard); - while let Some(next) = func(prev) { - match self.compare_exchange_weak(prev, next, set_order, fail_order, guard) { - Ok(shared) => return Ok(shared), - Err(next_prev) => prev = next_prev.current, - } - } - Err(prev) - } - - /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current - /// value is the same as `current`. The tag is also taken into account, so two pointers to the - /// same object, but with different tags, will not be considered equal. - /// - /// The return value is a result indicating whether the new pointer was written. On success the - /// pointer that was written is returned. On failure the actual current value and `new` are - /// returned. - /// - /// This method takes a [`CompareAndSetOrdering`] argument which describes the memory - /// ordering of this operation. - /// - /// # Migrating to `compare_exchange` - /// - /// `compare_and_set` is equivalent to `compare_exchange` with the following mapping for - /// memory orderings: - /// - /// Original | Success | Failure - /// -------- | ------- | ------- - /// Relaxed | Relaxed | Relaxed - /// Acquire | Acquire | Acquire - /// Release | Release | Relaxed - /// AcqRel | AcqRel | Acquire - /// SeqCst | SeqCst | SeqCst - /// - /// # Examples - /// - /// ``` - /// # #![allow(deprecated)] - /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// - /// let guard = &epoch::pin(); - /// let curr = a.load(SeqCst, guard); - /// let res1 = a.compare_and_set(curr, Shared::null(), SeqCst, guard); - /// let res2 = a.compare_and_set(curr, Owned::new(5678), SeqCst, guard); - /// # unsafe { drop(curr.into_owned()); } // avoid leak - /// ``` - // TODO: remove in the next major version. - #[allow(deprecated)] - #[deprecated(note = "Use `compare_exchange` instead")] - pub fn compare_and_set<'g, O, P>( - &self, - current: Shared<'_, T>, - new: P, - ord: O, - guard: &'g Guard, - ) -> Result, CompareAndSetError<'g, T, P>> - where - O: CompareAndSetOrdering, - P: Pointer, - { - self.compare_exchange(current, new, ord.success(), ord.failure(), guard) - } - - /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current - /// value is the same as `current`. The tag is also taken into account, so two pointers to the - /// same object, but with different tags, will not be considered equal. - /// - /// Unlike [`compare_and_set`], this method is allowed to spuriously fail even when comparison - /// succeeds, which can result in more efficient code on some platforms. The return value is a - /// result indicating whether the new pointer was written. On success the pointer that was - /// written is returned. On failure the actual current value and `new` are returned. - /// - /// This method takes a [`CompareAndSetOrdering`] argument which describes the memory - /// ordering of this operation. - /// - /// [`compare_and_set`]: Atomic::compare_and_set - /// - /// # Migrating to `compare_exchange_weak` - /// - /// `compare_and_set_weak` is equivalent to `compare_exchange_weak` with the following mapping for - /// memory orderings: - /// - /// Original | Success | Failure - /// -------- | ------- | ------- - /// Relaxed | Relaxed | Relaxed - /// Acquire | Acquire | Acquire - /// Release | Release | Relaxed - /// AcqRel | AcqRel | Acquire - /// SeqCst | SeqCst | SeqCst - /// - /// # Examples - /// - /// ``` - /// # #![allow(deprecated)] - /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// let guard = &epoch::pin(); - /// - /// let mut new = Owned::new(5678); - /// let mut ptr = a.load(SeqCst, guard); - /// # unsafe { drop(a.load(SeqCst, guard).into_owned()); } // avoid leak - /// loop { - /// match a.compare_and_set_weak(ptr, new, SeqCst, guard) { - /// Ok(p) => { - /// ptr = p; - /// break; - /// } - /// Err(err) => { - /// ptr = err.current; - /// new = err.new; - /// } - /// } - /// } - /// - /// let mut curr = a.load(SeqCst, guard); - /// loop { - /// match a.compare_and_set_weak(curr, Shared::null(), SeqCst, guard) { - /// Ok(_) => break, - /// Err(err) => curr = err.current, - /// } - /// } - /// # unsafe { drop(curr.into_owned()); } // avoid leak - /// ``` - // TODO: remove in the next major version. - #[allow(deprecated)] - #[deprecated(note = "Use `compare_exchange_weak` instead")] - pub fn compare_and_set_weak<'g, O, P>( - &self, - current: Shared<'_, T>, - new: P, - ord: O, - guard: &'g Guard, - ) -> Result, CompareAndSetError<'g, T, P>> - where - O: CompareAndSetOrdering, - P: Pointer, - { - self.compare_exchange_weak(current, new, ord.success(), ord.failure(), guard) - } - - /// Bitwise "and" with the current tag. - /// - /// Performs a bitwise "and" operation on the current tag and the argument `val`, and sets the - /// new tag to the result. Returns the previous pointer. - /// - /// This method takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::::from(Shared::null().with_tag(3)); - /// let guard = &epoch::pin(); - /// assert_eq!(a.fetch_and(2, SeqCst, guard).tag(), 3); - /// assert_eq!(a.load(SeqCst, guard).tag(), 2); - /// ``` - pub fn fetch_and<'g>(&self, val: usize, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { - unsafe { Shared::from_usize(self.data.fetch_and(val | !low_bits::(), ord)) } - } - - /// Bitwise "or" with the current tag. - /// - /// Performs a bitwise "or" operation on the current tag and the argument `val`, and sets the - /// new tag to the result. Returns the previous pointer. - /// - /// This method takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::::from(Shared::null().with_tag(1)); - /// let guard = &epoch::pin(); - /// assert_eq!(a.fetch_or(2, SeqCst, guard).tag(), 1); - /// assert_eq!(a.load(SeqCst, guard).tag(), 3); - /// ``` - pub fn fetch_or<'g>(&self, val: usize, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { - unsafe { Shared::from_usize(self.data.fetch_or(val & low_bits::(), ord)) } - } - - /// Bitwise "xor" with the current tag. - /// - /// Performs a bitwise "xor" operation on the current tag and the argument `val`, and sets the - /// new tag to the result. Returns the previous pointer. - /// - /// This method takes an [`Ordering`] argument which describes the memory ordering of this - /// operation. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Shared}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::::from(Shared::null().with_tag(1)); - /// let guard = &epoch::pin(); - /// assert_eq!(a.fetch_xor(3, SeqCst, guard).tag(), 1); - /// assert_eq!(a.load(SeqCst, guard).tag(), 2); - /// ``` - pub fn fetch_xor<'g>(&self, val: usize, ord: Ordering, _: &'g Guard) -> Shared<'g, T> { - unsafe { Shared::from_usize(self.data.fetch_xor(val & low_bits::(), ord)) } - } - - /// Takes ownership of the pointee. - /// - /// This consumes the atomic and converts it into [`Owned`]. As [`Atomic`] doesn't have a - /// destructor and doesn't drop the pointee while [`Owned`] does, this is suitable for - /// destructors of data structures. - /// - /// # Panics - /// - /// Panics if this pointer is null, but only in debug mode. - /// - /// # Safety - /// - /// This method may be called only if the pointer is valid and nobody else is holding a - /// reference to the same object. - /// - /// # Examples - /// - /// ```rust - /// # use std::mem; - /// # use crossbeam_epoch::Atomic; - /// struct DataStructure { - /// ptr: Atomic, - /// } - /// - /// impl Drop for DataStructure { - /// fn drop(&mut self) { - /// // By now the DataStructure lives only in our thread and we are sure we don't hold - /// // any Shared or & to it ourselves. - /// unsafe { - /// drop(mem::replace(&mut self.ptr, Atomic::null()).into_owned()); - /// } - /// } - /// } - /// ``` - pub unsafe fn into_owned(self) -> Owned { - Owned::from_usize(self.data.into_inner()) - } - - /// Takes ownership of the pointee if it is non-null. - /// - /// This consumes the atomic and converts it into [`Owned`]. As [`Atomic`] doesn't have a - /// destructor and doesn't drop the pointee while [`Owned`] does, this is suitable for - /// destructors of data structures. - /// - /// # Safety - /// - /// This method may be called only if the pointer is valid and nobody else is holding a - /// reference to the same object, or the pointer is null. - /// - /// # Examples - /// - /// ```rust - /// # use std::mem; - /// # use crossbeam_epoch::Atomic; - /// struct DataStructure { - /// ptr: Atomic, - /// } - /// - /// impl Drop for DataStructure { - /// fn drop(&mut self) { - /// // By now the DataStructure lives only in our thread and we are sure we don't hold - /// // any Shared or & to it ourselves, but it may be null, so we have to be careful. - /// let old = mem::replace(&mut self.ptr, Atomic::null()); - /// unsafe { - /// if let Some(x) = old.try_into_owned() { - /// drop(x) - /// } - /// } - /// } - /// } - /// ``` - pub unsafe fn try_into_owned(self) -> Option> { - let data = self.data.into_inner(); - if decompose_tag::(data).0 == 0 { - None - } else { - Some(Owned::from_usize(data)) - } - } -} - -impl fmt::Debug for Atomic { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let data = self.data.load(Ordering::SeqCst); - let (raw, tag) = decompose_tag::(data); - - f.debug_struct("Atomic") - .field("raw", &raw) - .field("tag", &tag) - .finish() - } -} - -impl fmt::Pointer for Atomic { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let data = self.data.load(Ordering::SeqCst); - let (raw, _) = decompose_tag::(data); - fmt::Pointer::fmt(&(unsafe { T::deref(raw) as *const _ }), f) - } -} - -impl Clone for Atomic { - /// Returns a copy of the atomic value. - /// - /// Note that a `Relaxed` load is used here. If you need synchronization, use it with other - /// atomics or fences. - fn clone(&self) -> Self { - let data = self.data.load(Ordering::Relaxed); - Atomic::from_usize(data) - } -} - -impl Default for Atomic { - fn default() -> Self { - Atomic::null() - } -} - -impl From> for Atomic { - /// Returns a new atomic pointer pointing to `owned`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{Atomic, Owned}; - /// - /// let a = Atomic::::from(Owned::new(1234)); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - fn from(owned: Owned) -> Self { - let data = owned.data; - mem::forget(owned); - Self::from_usize(data) - } -} - -impl From> for Atomic { - fn from(b: Box) -> Self { - Self::from(Owned::from(b)) - } -} - -impl From for Atomic { - fn from(t: T) -> Self { - Self::new(t) - } -} - -impl<'g, T: ?Sized + Pointable> From> for Atomic { - /// Returns a new atomic pointer pointing to `ptr`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{Atomic, Shared}; - /// - /// let a = Atomic::::from(Shared::::null()); - /// ``` - fn from(ptr: Shared<'g, T>) -> Self { - Self::from_usize(ptr.data) - } -} - -impl From<*const T> for Atomic { - /// Returns a new atomic pointer pointing to `raw`. - /// - /// # Examples - /// - /// ``` - /// use std::ptr; - /// use crossbeam_epoch::Atomic; - /// - /// let a = Atomic::::from(ptr::null::()); - /// ``` - fn from(raw: *const T) -> Self { - Self::from_usize(raw as usize) - } -} - -/// A trait for either `Owned` or `Shared` pointers. -pub trait Pointer { - /// Returns the machine representation of the pointer. - fn into_usize(self) -> usize; - - /// Returns a new pointer pointing to the tagged pointer `data`. - /// - /// # Safety - /// - /// The given `data` should have been created by `Pointer::into_usize()`, and one `data` should - /// not be converted back by `Pointer::from_usize()` multiple times. - unsafe fn from_usize(data: usize) -> Self; -} - -/// An owned heap-allocated object. -/// -/// This type is very similar to `Box`. -/// -/// The pointer must be properly aligned. Since it is aligned, a tag can be stored into the unused -/// least significant bits of the address. -pub struct Owned { - data: usize, - _marker: PhantomData>, -} - -impl Pointer for Owned { - #[inline] - fn into_usize(self) -> usize { - let data = self.data; - mem::forget(self); - data - } - - /// Returns a new pointer pointing to the tagged pointer `data`. - /// - /// # Panics - /// - /// Panics if the data is zero in debug mode. - #[inline] - unsafe fn from_usize(data: usize) -> Self { - debug_assert!(data != 0, "converting zero into `Owned`"); - Owned { - data, - _marker: PhantomData, - } - } -} - -impl Owned { - /// Returns a new owned pointer pointing to `raw`. - /// - /// This function is unsafe because improper use may lead to memory problems. Argument `raw` - /// must be a valid pointer. Also, a double-free may occur if the function is called twice on - /// the same raw pointer. - /// - /// # Panics - /// - /// Panics if `raw` is not properly aligned. - /// - /// # Safety - /// - /// The given `raw` should have been derived from `Owned`, and one `raw` should not be converted - /// back by `Owned::from_raw()` multiple times. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Owned; - /// - /// let o = unsafe { Owned::from_raw(Box::into_raw(Box::new(1234))) }; - /// ``` - pub unsafe fn from_raw(raw: *mut T) -> Owned { - let raw = raw as usize; - ensure_aligned::(raw); - Self::from_usize(raw) - } - - /// Converts the owned pointer into a `Box`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Owned; - /// - /// let o = Owned::new(1234); - /// let b: Box = o.into_box(); - /// assert_eq!(*b, 1234); - /// ``` - pub fn into_box(self) -> Box { - let (raw, _) = decompose_tag::(self.data); - mem::forget(self); - unsafe { Box::from_raw(raw as *mut _) } - } - - /// Allocates `value` on the heap and returns a new owned pointer pointing to it. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Owned; - /// - /// let o = Owned::new(1234); - /// ``` - pub fn new(init: T) -> Owned { - Self::init(init) - } -} - -impl Owned { - /// Allocates `value` on the heap and returns a new owned pointer pointing to it. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Owned; - /// - /// let o = Owned::::init(1234); - /// ``` - pub fn init(init: T::Init) -> Owned { - unsafe { Self::from_usize(T::init(init)) } - } - - /// Converts the owned pointer into a [`Shared`]. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Owned}; - /// - /// let o = Owned::new(1234); - /// let guard = &epoch::pin(); - /// let p = o.into_shared(guard); - /// # unsafe { drop(p.into_owned()); } // avoid leak - /// ``` - #[allow(clippy::needless_lifetimes)] - pub fn into_shared<'g>(self, _: &'g Guard) -> Shared<'g, T> { - unsafe { Shared::from_usize(self.into_usize()) } - } - - /// Returns the tag stored within the pointer. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Owned; - /// - /// assert_eq!(Owned::new(1234).tag(), 0); - /// ``` - pub fn tag(&self) -> usize { - let (_, tag) = decompose_tag::(self.data); - tag - } - - /// Returns the same pointer, but tagged with `tag`. `tag` is truncated to be fit into the - /// unused bits of the pointer to `T`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Owned; - /// - /// let o = Owned::new(0u64); - /// assert_eq!(o.tag(), 0); - /// let o = o.with_tag(2); - /// assert_eq!(o.tag(), 2); - /// ``` - pub fn with_tag(self, tag: usize) -> Owned { - let data = self.into_usize(); - unsafe { Self::from_usize(compose_tag::(data, tag)) } - } -} - -impl Drop for Owned { - fn drop(&mut self) { - let (raw, _) = decompose_tag::(self.data); - unsafe { - T::drop(raw); - } - } -} - -impl fmt::Debug for Owned { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (raw, tag) = decompose_tag::(self.data); - - f.debug_struct("Owned") - .field("raw", &raw) - .field("tag", &tag) - .finish() - } -} - -impl Clone for Owned { - fn clone(&self) -> Self { - Owned::new((**self).clone()).with_tag(self.tag()) - } -} - -impl Deref for Owned { - type Target = T; - - fn deref(&self) -> &T { - let (raw, _) = decompose_tag::(self.data); - unsafe { T::deref(raw) } - } -} - -impl DerefMut for Owned { - fn deref_mut(&mut self) -> &mut T { - let (raw, _) = decompose_tag::(self.data); - unsafe { T::deref_mut(raw) } - } -} - -impl From for Owned { - fn from(t: T) -> Self { - Owned::new(t) - } -} - -impl From> for Owned { - /// Returns a new owned pointer pointing to `b`. - /// - /// # Panics - /// - /// Panics if the pointer (the `Box`) is not properly aligned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Owned; - /// - /// let o = unsafe { Owned::from_raw(Box::into_raw(Box::new(1234))) }; - /// ``` - fn from(b: Box) -> Self { - unsafe { Self::from_raw(Box::into_raw(b)) } - } -} - -impl Borrow for Owned { - fn borrow(&self) -> &T { - self.deref() - } -} - -impl BorrowMut for Owned { - fn borrow_mut(&mut self) -> &mut T { - self.deref_mut() - } -} - -impl AsRef for Owned { - fn as_ref(&self) -> &T { - self.deref() - } -} - -impl AsMut for Owned { - fn as_mut(&mut self) -> &mut T { - self.deref_mut() - } -} - -/// A pointer to an object protected by the epoch GC. -/// -/// The pointer is valid for use only during the lifetime `'g`. -/// -/// The pointer must be properly aligned. Since it is aligned, a tag can be stored into the unused -/// least significant bits of the address. -pub struct Shared<'g, T: 'g + ?Sized + Pointable> { - data: usize, - _marker: PhantomData<(&'g (), *const T)>, -} - -impl Clone for Shared<'_, T> { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for Shared<'_, T> {} - -impl Pointer for Shared<'_, T> { - #[inline] - fn into_usize(self) -> usize { - self.data - } - - #[inline] - unsafe fn from_usize(data: usize) -> Self { - Shared { - data, - _marker: PhantomData, - } - } -} - -impl<'g, T> Shared<'g, T> { - /// Converts the pointer to a raw pointer (without the tag). - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let o = Owned::new(1234); - /// let raw = &*o as *const _; - /// let a = Atomic::from(o); - /// - /// let guard = &epoch::pin(); - /// let p = a.load(SeqCst, guard); - /// assert_eq!(p.as_raw(), raw); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn as_raw(&self) -> *const T { - let (raw, _) = decompose_tag::(self.data); - raw as *const _ - } -} - -impl<'g, T: ?Sized + Pointable> Shared<'g, T> { - /// Returns a new null pointer. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Shared; - /// - /// let p = Shared::::null(); - /// assert!(p.is_null()); - /// ``` - pub fn null() -> Shared<'g, T> { - Shared { - data: 0, - _marker: PhantomData, - } - } - - /// Returns `true` if the pointer is null. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::null(); - /// let guard = &epoch::pin(); - /// assert!(a.load(SeqCst, guard).is_null()); - /// a.store(Owned::new(1234), SeqCst); - /// assert!(!a.load(SeqCst, guard).is_null()); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn is_null(&self) -> bool { - let (raw, _) = decompose_tag::(self.data); - raw == 0 - } - - /// Dereferences the pointer. - /// - /// Returns a reference to the pointee that is valid during the lifetime `'g`. - /// - /// # Safety - /// - /// Dereferencing a pointer is unsafe because it could be pointing to invalid memory. - /// - /// Another concern is the possibility of data races due to lack of proper synchronization. - /// For example, consider the following scenario: - /// - /// 1. A thread creates a new object: `a.store(Owned::new(10), Relaxed)` - /// 2. Another thread reads it: `*a.load(Relaxed, guard).as_ref().unwrap()` - /// - /// The problem is that relaxed orderings don't synchronize initialization of the object with - /// the read from the second thread. This is a data race. A possible solution would be to use - /// `Release` and `Acquire` orderings. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// let guard = &epoch::pin(); - /// let p = a.load(SeqCst, guard); - /// unsafe { - /// assert_eq!(p.deref(), &1234); - /// } - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub unsafe fn deref(&self) -> &'g T { - let (raw, _) = decompose_tag::(self.data); - T::deref(raw) - } - - /// Dereferences the pointer. - /// - /// Returns a mutable reference to the pointee that is valid during the lifetime `'g`. - /// - /// # Safety - /// - /// * There is no guarantee that there are no more threads attempting to read/write from/to the - /// actual object at the same time. - /// - /// The user must know that there are no concurrent accesses towards the object itself. - /// - /// * Other than the above, all safety concerns of `deref()` applies here. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(vec![1, 2, 3, 4]); - /// let guard = &epoch::pin(); - /// - /// let mut p = a.load(SeqCst, guard); - /// unsafe { - /// assert!(!p.is_null()); - /// let b = p.deref_mut(); - /// assert_eq!(b, &vec![1, 2, 3, 4]); - /// b.push(5); - /// assert_eq!(b, &vec![1, 2, 3, 4, 5]); - /// } - /// - /// let p = a.load(SeqCst, guard); - /// unsafe { - /// assert_eq!(p.deref(), &vec![1, 2, 3, 4, 5]); - /// } - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub unsafe fn deref_mut(&mut self) -> &'g mut T { - let (raw, _) = decompose_tag::(self.data); - T::deref_mut(raw) - } - - /// Converts the pointer to a reference. - /// - /// Returns `None` if the pointer is null, or else a reference to the object wrapped in `Some`. - /// - /// # Safety - /// - /// Dereferencing a pointer is unsafe because it could be pointing to invalid memory. - /// - /// Another concern is the possibility of data races due to lack of proper synchronization. - /// For example, consider the following scenario: - /// - /// 1. A thread creates a new object: `a.store(Owned::new(10), Relaxed)` - /// 2. Another thread reads it: `*a.load(Relaxed, guard).as_ref().unwrap()` - /// - /// The problem is that relaxed orderings don't synchronize initialization of the object with - /// the read from the second thread. This is a data race. A possible solution would be to use - /// `Release` and `Acquire` orderings. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// let guard = &epoch::pin(); - /// let p = a.load(SeqCst, guard); - /// unsafe { - /// assert_eq!(p.as_ref(), Some(&1234)); - /// } - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub unsafe fn as_ref(&self) -> Option<&'g T> { - let (raw, _) = decompose_tag::(self.data); - if raw == 0 { - None - } else { - Some(T::deref(raw)) - } - } - - /// Takes ownership of the pointee. - /// - /// # Panics - /// - /// Panics if this pointer is null, but only in debug mode. - /// - /// # Safety - /// - /// This method may be called only if the pointer is valid and nobody else is holding a - /// reference to the same object. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// unsafe { - /// let guard = &epoch::unprotected(); - /// let p = a.load(SeqCst, guard); - /// drop(p.into_owned()); - /// } - /// ``` - pub unsafe fn into_owned(self) -> Owned { - debug_assert!(!self.is_null(), "converting a null `Shared` into `Owned`"); - Owned::from_usize(self.data) - } - - /// Takes ownership of the pointee if it is not null. - /// - /// # Safety - /// - /// This method may be called only if the pointer is valid and nobody else is holding a - /// reference to the same object, or if the pointer is null. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(1234); - /// unsafe { - /// let guard = &epoch::unprotected(); - /// let p = a.load(SeqCst, guard); - /// if let Some(x) = p.try_into_owned() { - /// drop(x); - /// } - /// } - /// ``` - pub unsafe fn try_into_owned(self) -> Option> { - if self.is_null() { - None - } else { - Some(Owned::from_usize(self.data)) - } - } - - /// Returns the tag stored within the pointer. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::::from(Owned::new(0u64).with_tag(2)); - /// let guard = &epoch::pin(); - /// let p = a.load(SeqCst, guard); - /// assert_eq!(p.tag(), 2); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn tag(&self) -> usize { - let (_, tag) = decompose_tag::(self.data); - tag - } - - /// Returns the same pointer, but tagged with `tag`. `tag` is truncated to be fit into the - /// unused bits of the pointer to `T`. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(0u64); - /// let guard = &epoch::pin(); - /// let p1 = a.load(SeqCst, guard); - /// let p2 = p1.with_tag(2); - /// - /// assert_eq!(p1.tag(), 0); - /// assert_eq!(p2.tag(), 2); - /// assert_eq!(p1.as_raw(), p2.as_raw()); - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn with_tag(&self, tag: usize) -> Shared<'g, T> { - unsafe { Self::from_usize(compose_tag::(self.data, tag)) } - } -} - -impl From<*const T> for Shared<'_, T> { - /// Returns a new pointer pointing to `raw`. - /// - /// # Panics - /// - /// Panics if `raw` is not properly aligned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::Shared; - /// - /// let p = Shared::from(Box::into_raw(Box::new(1234)) as *const _); - /// assert!(!p.is_null()); - /// # unsafe { drop(p.into_owned()); } // avoid leak - /// ``` - fn from(raw: *const T) -> Self { - let raw = raw as usize; - ensure_aligned::(raw); - unsafe { Self::from_usize(raw) } - } -} - -impl<'g, T: ?Sized + Pointable> PartialEq> for Shared<'g, T> { - fn eq(&self, other: &Self) -> bool { - self.data == other.data - } -} - -impl Eq for Shared<'_, T> {} - -impl<'g, T: ?Sized + Pointable> PartialOrd> for Shared<'g, T> { - fn partial_cmp(&self, other: &Self) -> Option { - self.data.partial_cmp(&other.data) - } -} - -impl Ord for Shared<'_, T> { - fn cmp(&self, other: &Self) -> cmp::Ordering { - self.data.cmp(&other.data) - } -} - -impl fmt::Debug for Shared<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (raw, tag) = decompose_tag::(self.data); - - f.debug_struct("Shared") - .field("raw", &raw) - .field("tag", &tag) - .finish() - } -} - -impl fmt::Pointer for Shared<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&(unsafe { self.deref() as *const _ }), f) - } -} - -impl Default for Shared<'_, T> { - fn default() -> Self { - Shared::null() - } -} - -#[cfg(all(test, not(crossbeam_loom)))] -mod tests { - use super::{Owned, Shared}; - use std::mem::MaybeUninit; - - #[test] - fn valid_tag_i8() { - Shared::::null().with_tag(0); - } - - #[test] - fn valid_tag_i64() { - Shared::::null().with_tag(7); - } - - #[test] - fn const_atomic_null() { - use super::Atomic; - static _U: Atomic = Atomic::::null(); - } - - #[test] - fn array_init() { - let owned = Owned::<[MaybeUninit]>::init(10); - let arr: &[MaybeUninit] = &owned; - assert_eq!(arr.len(), 10); - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/collector.rs b/third-party/vendor/crossbeam-epoch/src/collector.rs deleted file mode 100644 index 12655d6c..00000000 --- a/third-party/vendor/crossbeam-epoch/src/collector.rs +++ /dev/null @@ -1,464 +0,0 @@ -/// Epoch-based garbage collector. -/// -/// # Examples -/// -/// ``` -/// use crossbeam_epoch::Collector; -/// -/// let collector = Collector::new(); -/// -/// let handle = collector.register(); -/// drop(collector); // `handle` still works after dropping `collector` -/// -/// handle.pin().flush(); -/// ``` -use core::fmt; - -use crate::guard::Guard; -use crate::internal::{Global, Local}; -use crate::primitive::sync::Arc; - -/// An epoch-based garbage collector. -pub struct Collector { - pub(crate) global: Arc, -} - -unsafe impl Send for Collector {} -unsafe impl Sync for Collector {} - -impl Default for Collector { - fn default() -> Self { - Self { - global: Arc::new(Global::new()), - } - } -} - -impl Collector { - /// Creates a new collector. - pub fn new() -> Self { - Self::default() - } - - /// Registers a new handle for the collector. - pub fn register(&self) -> LocalHandle { - Local::register(self) - } -} - -impl Clone for Collector { - /// Creates another reference to the same garbage collector. - fn clone(&self) -> Self { - Collector { - global: self.global.clone(), - } - } -} - -impl fmt::Debug for Collector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Collector { .. }") - } -} - -impl PartialEq for Collector { - /// Checks if both handles point to the same collector. - fn eq(&self, rhs: &Collector) -> bool { - Arc::ptr_eq(&self.global, &rhs.global) - } -} -impl Eq for Collector {} - -/// A handle to a garbage collector. -pub struct LocalHandle { - pub(crate) local: *const Local, -} - -impl LocalHandle { - /// Pins the handle. - #[inline] - pub fn pin(&self) -> Guard { - unsafe { (*self.local).pin() } - } - - /// Returns `true` if the handle is pinned. - #[inline] - pub fn is_pinned(&self) -> bool { - unsafe { (*self.local).is_pinned() } - } - - /// Returns the `Collector` associated with this handle. - #[inline] - pub fn collector(&self) -> &Collector { - unsafe { (*self.local).collector() } - } -} - -impl Drop for LocalHandle { - #[inline] - fn drop(&mut self) { - unsafe { - Local::release_handle(&*self.local); - } - } -} - -impl fmt::Debug for LocalHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("LocalHandle { .. }") - } -} - -#[cfg(all(test, not(crossbeam_loom)))] -mod tests { - use std::mem::ManuallyDrop; - use std::sync::atomic::{AtomicUsize, Ordering}; - - use crossbeam_utils::thread; - - use crate::{Collector, Owned}; - - const NUM_THREADS: usize = 8; - - #[test] - fn pin_reentrant() { - let collector = Collector::new(); - let handle = collector.register(); - drop(collector); - - assert!(!handle.is_pinned()); - { - let _guard = &handle.pin(); - assert!(handle.is_pinned()); - { - let _guard = &handle.pin(); - assert!(handle.is_pinned()); - } - assert!(handle.is_pinned()); - } - assert!(!handle.is_pinned()); - } - - #[test] - fn flush_local_bag() { - let collector = Collector::new(); - let handle = collector.register(); - drop(collector); - - for _ in 0..100 { - let guard = &handle.pin(); - unsafe { - let a = Owned::new(7).into_shared(guard); - guard.defer_destroy(a); - - assert!(!(*guard.local).bag.with(|b| (*b).is_empty())); - - while !(*guard.local).bag.with(|b| (*b).is_empty()) { - guard.flush(); - } - } - } - } - - #[test] - fn garbage_buffering() { - let collector = Collector::new(); - let handle = collector.register(); - drop(collector); - - let guard = &handle.pin(); - unsafe { - for _ in 0..10 { - let a = Owned::new(7).into_shared(guard); - guard.defer_destroy(a); - } - assert!(!(*guard.local).bag.with(|b| (*b).is_empty())); - } - } - - #[test] - fn pin_holds_advance() { - #[cfg(miri)] - const N: usize = 500; - #[cfg(not(miri))] - const N: usize = 500_000; - - let collector = Collector::new(); - - thread::scope(|scope| { - for _ in 0..NUM_THREADS { - scope.spawn(|_| { - let handle = collector.register(); - for _ in 0..N { - let guard = &handle.pin(); - - let before = collector.global.epoch.load(Ordering::Relaxed); - collector.global.collect(guard); - let after = collector.global.epoch.load(Ordering::Relaxed); - - assert!(after.wrapping_sub(before) <= 2); - } - }); - } - }) - .unwrap(); - } - - #[cfg(not(crossbeam_sanitize))] // TODO: assertions failed due to `cfg(crossbeam_sanitize)` reduce `internal::MAX_OBJECTS` - #[test] - fn incremental() { - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - static DESTROYS: AtomicUsize = AtomicUsize::new(0); - - let collector = Collector::new(); - let handle = collector.register(); - - unsafe { - let guard = &handle.pin(); - for _ in 0..COUNT { - let a = Owned::new(7i32).into_shared(guard); - guard.defer_unchecked(move || { - drop(a.into_owned()); - DESTROYS.fetch_add(1, Ordering::Relaxed); - }); - } - guard.flush(); - } - - let mut last = 0; - - while last < COUNT { - let curr = DESTROYS.load(Ordering::Relaxed); - assert!(curr - last <= 1024); - last = curr; - - let guard = &handle.pin(); - collector.global.collect(guard); - } - assert!(DESTROYS.load(Ordering::Relaxed) == COUNT); - } - - #[test] - fn buffering() { - const COUNT: usize = 10; - #[cfg(miri)] - const N: usize = 500; - #[cfg(not(miri))] - const N: usize = 100_000; - static DESTROYS: AtomicUsize = AtomicUsize::new(0); - - let collector = Collector::new(); - let handle = collector.register(); - - unsafe { - let guard = &handle.pin(); - for _ in 0..COUNT { - let a = Owned::new(7i32).into_shared(guard); - guard.defer_unchecked(move || { - drop(a.into_owned()); - DESTROYS.fetch_add(1, Ordering::Relaxed); - }); - } - } - - for _ in 0..N { - collector.global.collect(&handle.pin()); - } - assert!(DESTROYS.load(Ordering::Relaxed) < COUNT); - - handle.pin().flush(); - - while DESTROYS.load(Ordering::Relaxed) < COUNT { - let guard = &handle.pin(); - collector.global.collect(guard); - } - assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT); - } - - #[test] - fn count_drops() { - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - static DROPS: AtomicUsize = AtomicUsize::new(0); - - struct Elem(#[allow(dead_code)] i32); - - impl Drop for Elem { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::Relaxed); - } - } - - let collector = Collector::new(); - let handle = collector.register(); - - unsafe { - let guard = &handle.pin(); - - for _ in 0..COUNT { - let a = Owned::new(Elem(7i32)).into_shared(guard); - guard.defer_destroy(a); - } - guard.flush(); - } - - while DROPS.load(Ordering::Relaxed) < COUNT { - let guard = &handle.pin(); - collector.global.collect(guard); - } - assert_eq!(DROPS.load(Ordering::Relaxed), COUNT); - } - - #[test] - fn count_destroy() { - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - static DESTROYS: AtomicUsize = AtomicUsize::new(0); - - let collector = Collector::new(); - let handle = collector.register(); - - unsafe { - let guard = &handle.pin(); - - for _ in 0..COUNT { - let a = Owned::new(7i32).into_shared(guard); - guard.defer_unchecked(move || { - drop(a.into_owned()); - DESTROYS.fetch_add(1, Ordering::Relaxed); - }); - } - guard.flush(); - } - - while DESTROYS.load(Ordering::Relaxed) < COUNT { - let guard = &handle.pin(); - collector.global.collect(guard); - } - assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT); - } - - #[test] - fn drop_array() { - const COUNT: usize = 700; - static DROPS: AtomicUsize = AtomicUsize::new(0); - - struct Elem(#[allow(dead_code)] i32); - - impl Drop for Elem { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::Relaxed); - } - } - - let collector = Collector::new(); - let handle = collector.register(); - - let mut guard = handle.pin(); - - let mut v = Vec::with_capacity(COUNT); - for i in 0..COUNT { - v.push(Elem(i as i32)); - } - - { - let a = Owned::new(v).into_shared(&guard); - unsafe { - guard.defer_destroy(a); - } - guard.flush(); - } - - while DROPS.load(Ordering::Relaxed) < COUNT { - guard.repin(); - collector.global.collect(&guard); - } - assert_eq!(DROPS.load(Ordering::Relaxed), COUNT); - } - - #[test] - fn destroy_array() { - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - static DESTROYS: AtomicUsize = AtomicUsize::new(0); - - let collector = Collector::new(); - let handle = collector.register(); - - unsafe { - let guard = &handle.pin(); - - let mut v = Vec::with_capacity(COUNT); - for i in 0..COUNT { - v.push(i as i32); - } - - let len = v.len(); - let cap = v.capacity(); - let ptr = ManuallyDrop::new(v).as_mut_ptr(); - guard.defer_unchecked(move || { - drop(Vec::from_raw_parts(ptr, len, cap)); - DESTROYS.fetch_add(len, Ordering::Relaxed); - }); - guard.flush(); - } - - while DESTROYS.load(Ordering::Relaxed) < COUNT { - let guard = &handle.pin(); - collector.global.collect(guard); - } - assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT); - } - - #[test] - fn stress() { - const THREADS: usize = 8; - #[cfg(miri)] - const COUNT: usize = 500; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - static DROPS: AtomicUsize = AtomicUsize::new(0); - - struct Elem(#[allow(dead_code)] i32); - - impl Drop for Elem { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::Relaxed); - } - } - - let collector = Collector::new(); - - thread::scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - let handle = collector.register(); - for _ in 0..COUNT { - let guard = &handle.pin(); - unsafe { - let a = Owned::new(Elem(7i32)).into_shared(guard); - guard.defer_destroy(a); - } - } - }); - } - }) - .unwrap(); - - let handle = collector.register(); - while DROPS.load(Ordering::Relaxed) < COUNT * THREADS { - let guard = &handle.pin(); - collector.global.collect(guard); - } - assert_eq!(DROPS.load(Ordering::Relaxed), COUNT * THREADS); - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/default.rs b/third-party/vendor/crossbeam-epoch/src/default.rs deleted file mode 100644 index a9790a37..00000000 --- a/third-party/vendor/crossbeam-epoch/src/default.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! The default garbage collector. -//! -//! For each thread, a participant is lazily initialized on its first use, when the current thread -//! is registered in the default collector. If initialized, the thread's participant will get -//! destructed on thread exit, which in turn unregisters the thread. - -use crate::collector::{Collector, LocalHandle}; -use crate::guard::Guard; -use crate::primitive::thread_local; -#[cfg(not(crossbeam_loom))] -use crate::sync::once_lock::OnceLock; - -fn collector() -> &'static Collector { - #[cfg(not(crossbeam_loom))] - { - /// The global data for the default garbage collector. - static COLLECTOR: OnceLock = OnceLock::new(); - COLLECTOR.get_or_init(Collector::new) - } - // FIXME: loom does not currently provide the equivalent of Lazy: - // https://github.com/tokio-rs/loom/issues/263 - #[cfg(crossbeam_loom)] - { - loom::lazy_static! { - /// The global data for the default garbage collector. - static ref COLLECTOR: Collector = Collector::new(); - } - &COLLECTOR - } -} - -thread_local! { - /// The per-thread participant for the default garbage collector. - static HANDLE: LocalHandle = collector().register(); -} - -/// Pins the current thread. -#[inline] -pub fn pin() -> Guard { - with_handle(|handle| handle.pin()) -} - -/// Returns `true` if the current thread is pinned. -#[inline] -pub fn is_pinned() -> bool { - with_handle(|handle| handle.is_pinned()) -} - -/// Returns the default global collector. -pub fn default_collector() -> &'static Collector { - collector() -} - -#[inline] -fn with_handle(mut f: F) -> R -where - F: FnMut(&LocalHandle) -> R, -{ - HANDLE - .try_with(|h| f(h)) - .unwrap_or_else(|_| f(&collector().register())) -} - -#[cfg(all(test, not(crossbeam_loom)))] -mod tests { - use crossbeam_utils::thread; - - #[test] - fn pin_while_exiting() { - struct Foo; - - impl Drop for Foo { - fn drop(&mut self) { - // Pin after `HANDLE` has been dropped. This must not panic. - super::pin(); - } - } - - thread_local! { - static FOO: Foo = const { Foo }; - } - - thread::scope(|scope| { - scope.spawn(|_| { - // Initialize `FOO` and then `HANDLE`. - FOO.with(|_| ()); - super::pin(); - // At thread exit, `HANDLE` gets dropped first and `FOO` second. - }); - }) - .unwrap(); - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/deferred.rs b/third-party/vendor/crossbeam-epoch/src/deferred.rs deleted file mode 100644 index 041955f5..00000000 --- a/third-party/vendor/crossbeam-epoch/src/deferred.rs +++ /dev/null @@ -1,146 +0,0 @@ -use alloc::boxed::Box; -use core::fmt; -use core::marker::PhantomData; -use core::mem::{self, MaybeUninit}; -use core::ptr; - -/// Number of words a piece of `Data` can hold. -/// -/// Three words should be enough for the majority of cases. For example, you can fit inside it the -/// function pointer together with a fat pointer representing an object that needs to be destroyed. -const DATA_WORDS: usize = 3; - -/// Some space to keep a `FnOnce()` object on the stack. -type Data = [usize; DATA_WORDS]; - -/// A `FnOnce()` that is stored inline if small, or otherwise boxed on the heap. -/// -/// This is a handy way of keeping an unsized `FnOnce()` within a sized structure. -pub(crate) struct Deferred { - call: unsafe fn(*mut u8), - data: MaybeUninit, - _marker: PhantomData<*mut ()>, // !Send + !Sync -} - -impl fmt::Debug for Deferred { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.pad("Deferred { .. }") - } -} - -impl Deferred { - pub(crate) const NO_OP: Self = { - fn no_op_call(_raw: *mut u8) {} - Self { - call: no_op_call, - data: MaybeUninit::uninit(), - _marker: PhantomData, - } - }; - - /// Constructs a new `Deferred` from a `FnOnce()`. - pub(crate) fn new(f: F) -> Self { - let size = mem::size_of::(); - let align = mem::align_of::(); - - unsafe { - if size <= mem::size_of::() && align <= mem::align_of::() { - let mut data = MaybeUninit::::uninit(); - ptr::write(data.as_mut_ptr().cast::(), f); - - unsafe fn call(raw: *mut u8) { - let f: F = ptr::read(raw.cast::()); - f(); - } - - Deferred { - call: call::, - data, - _marker: PhantomData, - } - } else { - let b: Box = Box::new(f); - let mut data = MaybeUninit::::uninit(); - ptr::write(data.as_mut_ptr().cast::>(), b); - - unsafe fn call(raw: *mut u8) { - // It's safe to cast `raw` from `*mut u8` to `*mut Box`, because `raw` is - // originally derived from `*mut Box`. - let b: Box = ptr::read(raw.cast::>()); - (*b)(); - } - - Deferred { - call: call::, - data, - _marker: PhantomData, - } - } - } - } - - /// Calls the function. - #[inline] - pub(crate) fn call(mut self) { - let call = self.call; - unsafe { call(self.data.as_mut_ptr().cast::()) }; - } -} - -#[cfg(all(test, not(crossbeam_loom)))] -mod tests { - use super::Deferred; - use std::cell::Cell; - use std::convert::identity; - - #[test] - fn on_stack() { - let fired = &Cell::new(false); - let a = [0usize; 1]; - - let d = Deferred::new(move || { - let _ = identity(a); - fired.set(true); - }); - - assert!(!fired.get()); - d.call(); - assert!(fired.get()); - } - - #[test] - fn on_heap() { - let fired = &Cell::new(false); - let a = [0usize; 10]; - - let d = Deferred::new(move || { - let _ = identity(a); - fired.set(true); - }); - - assert!(!fired.get()); - d.call(); - assert!(fired.get()); - } - - #[test] - fn string() { - let a = "hello".to_string(); - let d = Deferred::new(move || assert_eq!(a, "hello")); - d.call(); - } - - #[test] - fn boxed_slice_i32() { - let a: Box<[i32]> = vec![2, 3, 5, 7].into_boxed_slice(); - let d = Deferred::new(move || assert_eq!(*a, [2, 3, 5, 7])); - d.call(); - } - - #[test] - fn long_slice_usize() { - let a: [usize; 5] = [2, 3, 5, 7, 11]; - let d = Deferred::new(move || assert_eq!(a, [2, 3, 5, 7, 11])); - d.call(); - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/epoch.rs b/third-party/vendor/crossbeam-epoch/src/epoch.rs deleted file mode 100644 index 18d7418a..00000000 --- a/third-party/vendor/crossbeam-epoch/src/epoch.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! The global epoch -//! -//! The last bit in this number is unused and is always zero. Every so often the global epoch is -//! incremented, i.e. we say it "advances". A pinned participant may advance the global epoch only -//! if all currently pinned participants have been pinned in the current epoch. -//! -//! If an object became garbage in some epoch, then we can be sure that after two advancements no -//! participant will hold a reference to it. That is the crux of safe memory reclamation. - -use crate::primitive::sync::atomic::{AtomicUsize, Ordering}; - -/// An epoch that can be marked as pinned or unpinned. -/// -/// Internally, the epoch is represented as an integer that wraps around at some unspecified point -/// and a flag that represents whether it is pinned or unpinned. -#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] -pub(crate) struct Epoch { - /// The least significant bit is set if pinned. The rest of the bits hold the epoch. - data: usize, -} - -impl Epoch { - /// Returns the starting epoch in unpinned state. - #[inline] - pub(crate) fn starting() -> Self { - Self::default() - } - - /// Returns the number of epochs `self` is ahead of `rhs`. - /// - /// Internally, epochs are represented as numbers in the range `(isize::MIN / 2) .. (isize::MAX - /// / 2)`, so the returned distance will be in the same interval. - pub(crate) fn wrapping_sub(self, rhs: Self) -> isize { - // The result is the same with `(self.data & !1).wrapping_sub(rhs.data & !1) as isize >> 1`, - // because the possible difference of LSB in `(self.data & !1).wrapping_sub(rhs.data & !1)` - // will be ignored in the shift operation. - self.data.wrapping_sub(rhs.data & !1) as isize >> 1 - } - - /// Returns `true` if the epoch is marked as pinned. - #[inline] - pub(crate) fn is_pinned(self) -> bool { - (self.data & 1) == 1 - } - - /// Returns the same epoch, but marked as pinned. - #[inline] - pub(crate) fn pinned(self) -> Epoch { - Epoch { - data: self.data | 1, - } - } - - /// Returns the same epoch, but marked as unpinned. - #[inline] - pub(crate) fn unpinned(self) -> Epoch { - Epoch { - data: self.data & !1, - } - } - - /// Returns the successor epoch. - /// - /// The returned epoch will be marked as pinned only if the previous one was as well. - #[inline] - pub(crate) fn successor(self) -> Epoch { - Epoch { - data: self.data.wrapping_add(2), - } - } -} - -/// An atomic value that holds an `Epoch`. -#[derive(Default, Debug)] -pub(crate) struct AtomicEpoch { - /// Since `Epoch` is just a wrapper around `usize`, an `AtomicEpoch` is similarly represented - /// using an `AtomicUsize`. - data: AtomicUsize, -} - -impl AtomicEpoch { - /// Creates a new atomic epoch. - #[inline] - pub(crate) fn new(epoch: Epoch) -> Self { - let data = AtomicUsize::new(epoch.data); - AtomicEpoch { data } - } - - /// Loads a value from the atomic epoch. - #[inline] - pub(crate) fn load(&self, ord: Ordering) -> Epoch { - Epoch { - data: self.data.load(ord), - } - } - - /// Stores a value into the atomic epoch. - #[inline] - pub(crate) fn store(&self, epoch: Epoch, ord: Ordering) { - self.data.store(epoch.data, ord); - } - - /// Stores a value into the atomic epoch if the current value is the same as `current`. - /// - /// The return value is a result indicating whether the new value was written and containing - /// the previous value. On success this value is guaranteed to be equal to `current`. - /// - /// This method takes two `Ordering` arguments to describe the memory - /// ordering of this operation. `success` describes the required ordering for the - /// read-modify-write operation that takes place if the comparison with `current` succeeds. - /// `failure` describes the required ordering for the load operation that takes place when - /// the comparison fails. Using `Acquire` as success ordering makes the store part - /// of this operation `Relaxed`, and using `Release` makes the successful load - /// `Relaxed`. The failure ordering can only be `SeqCst`, `Acquire` or `Relaxed` - /// and must be equivalent to or weaker than the success ordering. - #[inline] - pub(crate) fn compare_exchange( - &self, - current: Epoch, - new: Epoch, - success: Ordering, - failure: Ordering, - ) -> Result { - match self - .data - .compare_exchange(current.data, new.data, success, failure) - { - Ok(data) => Ok(Epoch { data }), - Err(data) => Err(Epoch { data }), - } - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/guard.rs b/third-party/vendor/crossbeam-epoch/src/guard.rs deleted file mode 100644 index 5fe33807..00000000 --- a/third-party/vendor/crossbeam-epoch/src/guard.rs +++ /dev/null @@ -1,523 +0,0 @@ -use core::fmt; -use core::mem; - -use crate::atomic::Shared; -use crate::collector::Collector; -use crate::deferred::Deferred; -use crate::internal::Local; - -/// A guard that keeps the current thread pinned. -/// -/// # Pinning -/// -/// The current thread is pinned by calling [`pin`], which returns a new guard: -/// -/// ``` -/// use crossbeam_epoch as epoch; -/// -/// // It is often convenient to prefix a call to `pin` with a `&` in order to create a reference. -/// // This is not really necessary, but makes passing references to the guard a bit easier. -/// let guard = &epoch::pin(); -/// ``` -/// -/// When a guard gets dropped, the current thread is automatically unpinned. -/// -/// # Pointers on the stack -/// -/// Having a guard allows us to create pointers on the stack to heap-allocated objects. -/// For example: -/// -/// ``` -/// use crossbeam_epoch::{self as epoch, Atomic}; -/// use std::sync::atomic::Ordering::SeqCst; -/// -/// // Create a heap-allocated number. -/// let a = Atomic::new(777); -/// -/// // Pin the current thread. -/// let guard = &epoch::pin(); -/// -/// // Load the heap-allocated object and create pointer `p` on the stack. -/// let p = a.load(SeqCst, guard); -/// -/// // Dereference the pointer and print the value: -/// if let Some(num) = unsafe { p.as_ref() } { -/// println!("The number is {}.", num); -/// } -/// # unsafe { drop(a.into_owned()); } // avoid leak -/// ``` -/// -/// # Multiple guards -/// -/// Pinning is reentrant and it is perfectly legal to create multiple guards. In that case, the -/// thread will actually be pinned only when the first guard is created and unpinned when the last -/// one is dropped: -/// -/// ``` -/// use crossbeam_epoch as epoch; -/// -/// let guard1 = epoch::pin(); -/// let guard2 = epoch::pin(); -/// assert!(epoch::is_pinned()); -/// drop(guard1); -/// assert!(epoch::is_pinned()); -/// drop(guard2); -/// assert!(!epoch::is_pinned()); -/// ``` -/// -/// [`pin`]: super::pin -pub struct Guard { - pub(crate) local: *const Local, -} - -impl Guard { - /// Stores a function so that it can be executed at some point after all currently pinned - /// threads get unpinned. - /// - /// This method first stores `f` into the thread-local (or handle-local) cache. If this cache - /// becomes full, some functions are moved into the global cache. At the same time, some - /// functions from both local and global caches may get executed in order to incrementally - /// clean up the caches as they fill up. - /// - /// There is no guarantee when exactly `f` will be executed. The only guarantee is that it - /// won't be executed until all currently pinned threads get unpinned. In theory, `f` might - /// never run, but the epoch-based garbage collection will make an effort to execute it - /// reasonably soon. - /// - /// If this method is called from an [`unprotected`] guard, the function will simply be - /// executed immediately. - pub fn defer(&self, f: F) - where - F: FnOnce() -> R, - F: Send + 'static, - { - unsafe { - self.defer_unchecked(f); - } - } - - /// Stores a function so that it can be executed at some point after all currently pinned - /// threads get unpinned. - /// - /// This method first stores `f` into the thread-local (or handle-local) cache. If this cache - /// becomes full, some functions are moved into the global cache. At the same time, some - /// functions from both local and global caches may get executed in order to incrementally - /// clean up the caches as they fill up. - /// - /// There is no guarantee when exactly `f` will be executed. The only guarantee is that it - /// won't be executed until all currently pinned threads get unpinned. In theory, `f` might - /// never run, but the epoch-based garbage collection will make an effort to execute it - /// reasonably soon. - /// - /// If this method is called from an [`unprotected`] guard, the function will simply be - /// executed immediately. - /// - /// # Safety - /// - /// The given function must not hold reference onto the stack. It is highly recommended that - /// the passed function is **always** marked with `move` in order to prevent accidental - /// borrows. - /// - /// ``` - /// use crossbeam_epoch as epoch; - /// - /// let guard = &epoch::pin(); - /// let message = "Hello!"; - /// unsafe { - /// // ALWAYS use `move` when sending a closure into `defer_unchecked`. - /// guard.defer_unchecked(move || { - /// println!("{}", message); - /// }); - /// } - /// ``` - /// - /// Apart from that, keep in mind that another thread may execute `f`, so anything accessed by - /// the closure must be `Send`. - /// - /// We intentionally didn't require `F: Send`, because Rust's type systems usually cannot prove - /// `F: Send` for typical use cases. For example, consider the following code snippet, which - /// exemplifies the typical use case of deferring the deallocation of a shared reference: - /// - /// ```ignore - /// let shared = Owned::new(7i32).into_shared(guard); - /// guard.defer_unchecked(move || shared.into_owned()); // `Shared` is not `Send`! - /// ``` - /// - /// While `Shared` is not `Send`, it's safe for another thread to call the deferred function, - /// because it's called only after the grace period and `shared` is no longer shared with other - /// threads. But we don't expect type systems to prove this. - /// - /// # Examples - /// - /// When a heap-allocated object in a data structure becomes unreachable, it has to be - /// deallocated. However, the current thread and other threads may be still holding references - /// on the stack to that same object. Therefore it cannot be deallocated before those references - /// get dropped. This method can defer deallocation until all those threads get unpinned and - /// consequently drop all their references on the stack. - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new("foo"); - /// - /// // Now suppose that `a` is shared among multiple threads and concurrently - /// // accessed and modified... - /// - /// // Pin the current thread. - /// let guard = &epoch::pin(); - /// - /// // Steal the object currently stored in `a` and swap it with another one. - /// let p = a.swap(Owned::new("bar").into_shared(guard), SeqCst, guard); - /// - /// if !p.is_null() { - /// // The object `p` is pointing to is now unreachable. - /// // Defer its deallocation until all currently pinned threads get unpinned. - /// unsafe { - /// // ALWAYS use `move` when sending a closure into `defer_unchecked`. - /// guard.defer_unchecked(move || { - /// println!("{} is now being deallocated.", p.deref()); - /// // Now we have unique access to the object pointed to by `p` and can turn it - /// // into an `Owned`. Dropping the `Owned` will deallocate the object. - /// drop(p.into_owned()); - /// }); - /// } - /// } - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub unsafe fn defer_unchecked(&self, f: F) - where - F: FnOnce() -> R, - { - if let Some(local) = self.local.as_ref() { - local.defer(Deferred::new(move || drop(f())), self); - } else { - drop(f()); - } - } - - /// Stores a destructor for an object so that it can be deallocated and dropped at some point - /// after all currently pinned threads get unpinned. - /// - /// This method first stores the destructor into the thread-local (or handle-local) cache. If - /// this cache becomes full, some destructors are moved into the global cache. At the same - /// time, some destructors from both local and global caches may get executed in order to - /// incrementally clean up the caches as they fill up. - /// - /// There is no guarantee when exactly the destructor will be executed. The only guarantee is - /// that it won't be executed until all currently pinned threads get unpinned. In theory, the - /// destructor might never run, but the epoch-based garbage collection will make an effort to - /// execute it reasonably soon. - /// - /// If this method is called from an [`unprotected`] guard, the destructor will simply be - /// executed immediately. - /// - /// # Safety - /// - /// The object must not be reachable by other threads anymore, otherwise it might be still in - /// use when the destructor runs. - /// - /// Apart from that, keep in mind that another thread may execute the destructor, so the object - /// must be sendable to other threads. - /// - /// We intentionally didn't require `T: Send`, because Rust's type systems usually cannot prove - /// `T: Send` for typical use cases. For example, consider the following code snippet, which - /// exemplifies the typical use case of deferring the deallocation of a shared reference: - /// - /// ```ignore - /// let shared = Owned::new(7i32).into_shared(guard); - /// guard.defer_destroy(shared); // `Shared` is not `Send`! - /// ``` - /// - /// While `Shared` is not `Send`, it's safe for another thread to call the destructor, because - /// it's called only after the grace period and `shared` is no longer shared with other - /// threads. But we don't expect type systems to prove this. - /// - /// # Examples - /// - /// When a heap-allocated object in a data structure becomes unreachable, it has to be - /// deallocated. However, the current thread and other threads may be still holding references - /// on the stack to that same object. Therefore it cannot be deallocated before those references - /// get dropped. This method can defer deallocation until all those threads get unpinned and - /// consequently drop all their references on the stack. - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic, Owned}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new("foo"); - /// - /// // Now suppose that `a` is shared among multiple threads and concurrently - /// // accessed and modified... - /// - /// // Pin the current thread. - /// let guard = &epoch::pin(); - /// - /// // Steal the object currently stored in `a` and swap it with another one. - /// let p = a.swap(Owned::new("bar").into_shared(guard), SeqCst, guard); - /// - /// if !p.is_null() { - /// // The object `p` is pointing to is now unreachable. - /// // Defer its deallocation until all currently pinned threads get unpinned. - /// unsafe { - /// guard.defer_destroy(p); - /// } - /// } - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub unsafe fn defer_destroy(&self, ptr: Shared<'_, T>) { - self.defer_unchecked(move || ptr.into_owned()); - } - - /// Clears up the thread-local cache of deferred functions by executing them or moving into the - /// global cache. - /// - /// Call this method after deferring execution of a function if you want to get it executed as - /// soon as possible. Flushing will make sure it is residing in in the global cache, so that - /// any thread has a chance of taking the function and executing it. - /// - /// If this method is called from an [`unprotected`] guard, it is a no-op (nothing happens). - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch as epoch; - /// - /// let guard = &epoch::pin(); - /// guard.defer(move || { - /// println!("This better be printed as soon as possible!"); - /// }); - /// guard.flush(); - /// ``` - pub fn flush(&self) { - if let Some(local) = unsafe { self.local.as_ref() } { - local.flush(self); - } - } - - /// Unpins and then immediately re-pins the thread. - /// - /// This method is useful when you don't want delay the advancement of the global epoch by - /// holding an old epoch. For safety, you should not maintain any guard-based reference across - /// the call (the latter is enforced by `&mut self`). The thread will only be repinned if this - /// is the only active guard for the current thread. - /// - /// If this method is called from an [`unprotected`] guard, then the call will be just no-op. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// - /// let a = Atomic::new(777); - /// let mut guard = epoch::pin(); - /// { - /// let p = a.load(SeqCst, &guard); - /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); - /// } - /// guard.repin(); - /// { - /// let p = a.load(SeqCst, &guard); - /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); - /// } - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn repin(&mut self) { - if let Some(local) = unsafe { self.local.as_ref() } { - local.repin(); - } - } - - /// Temporarily unpins the thread, executes the given function and then re-pins the thread. - /// - /// This method is useful when you need to perform a long-running operation (e.g. sleeping) - /// and don't need to maintain any guard-based reference across the call (the latter is enforced - /// by `&mut self`). The thread will only be unpinned if this is the only active guard for the - /// current thread. - /// - /// If this method is called from an [`unprotected`] guard, then the passed function is called - /// directly without unpinning the thread. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch::{self as epoch, Atomic}; - /// use std::sync::atomic::Ordering::SeqCst; - /// use std::thread; - /// use std::time::Duration; - /// - /// let a = Atomic::new(777); - /// let mut guard = epoch::pin(); - /// { - /// let p = a.load(SeqCst, &guard); - /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); - /// } - /// guard.repin_after(|| thread::sleep(Duration::from_millis(50))); - /// { - /// let p = a.load(SeqCst, &guard); - /// assert_eq!(unsafe { p.as_ref() }, Some(&777)); - /// } - /// # unsafe { drop(a.into_owned()); } // avoid leak - /// ``` - pub fn repin_after(&mut self, f: F) -> R - where - F: FnOnce() -> R, - { - // Ensure the Guard is re-pinned even if the function panics - struct ScopeGuard(*const Local); - impl Drop for ScopeGuard { - fn drop(&mut self) { - if let Some(local) = unsafe { self.0.as_ref() } { - mem::forget(local.pin()); - local.release_handle(); - } - } - } - - if let Some(local) = unsafe { self.local.as_ref() } { - // We need to acquire a handle here to ensure the Local doesn't - // disappear from under us. - local.acquire_handle(); - local.unpin(); - } - - let _guard = ScopeGuard(self.local); - - f() - } - - /// Returns the `Collector` associated with this guard. - /// - /// This method is useful when you need to ensure that all guards used with - /// a data structure come from the same collector. - /// - /// If this method is called from an [`unprotected`] guard, then `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_epoch as epoch; - /// - /// let guard1 = epoch::pin(); - /// let guard2 = epoch::pin(); - /// assert!(guard1.collector() == guard2.collector()); - /// ``` - pub fn collector(&self) -> Option<&Collector> { - unsafe { self.local.as_ref().map(|local| local.collector()) } - } -} - -impl Drop for Guard { - #[inline] - fn drop(&mut self) { - if let Some(local) = unsafe { self.local.as_ref() } { - local.unpin(); - } - } -} - -impl fmt::Debug for Guard { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Guard { .. }") - } -} - -/// Returns a reference to a dummy guard that allows unprotected access to [`Atomic`]s. -/// -/// This guard should be used in special occasions only. Note that it doesn't actually keep any -/// thread pinned - it's just a fake guard that allows loading from [`Atomic`]s unsafely. -/// -/// Note that calling [`defer`] with a dummy guard will not defer the function - it will just -/// execute the function immediately. -/// -/// If necessary, it's possible to create more dummy guards by cloning: `unprotected().clone()`. -/// -/// # Safety -/// -/// Loading and dereferencing data from an [`Atomic`] using this guard is safe only if the -/// [`Atomic`] is not being concurrently modified by other threads. -/// -/// # Examples -/// -/// ``` -/// use crossbeam_epoch::{self as epoch, Atomic}; -/// use std::sync::atomic::Ordering::Relaxed; -/// -/// let a = Atomic::new(7); -/// -/// unsafe { -/// // Load `a` without pinning the current thread. -/// a.load(Relaxed, epoch::unprotected()); -/// -/// // It's possible to create more dummy guards. -/// let dummy = epoch::unprotected(); -/// -/// dummy.defer(move || { -/// println!("This gets executed immediately."); -/// }); -/// -/// // Dropping `dummy` doesn't affect the current thread - it's just a noop. -/// } -/// # unsafe { drop(a.into_owned()); } // avoid leak -/// ``` -/// -/// The most common use of this function is when constructing or destructing a data structure. -/// -/// For example, we can use a dummy guard in the destructor of a Treiber stack because at that -/// point no other thread could concurrently modify the [`Atomic`]s we are accessing. -/// -/// If we were to actually pin the current thread during destruction, that would just unnecessarily -/// delay garbage collection and incur some performance cost, so in cases like these `unprotected` -/// is very helpful. -/// -/// ``` -/// use crossbeam_epoch::{self as epoch, Atomic}; -/// use std::mem::ManuallyDrop; -/// use std::sync::atomic::Ordering::Relaxed; -/// -/// struct Stack { -/// head: Atomic>, -/// } -/// -/// struct Node { -/// data: ManuallyDrop, -/// next: Atomic>, -/// } -/// -/// impl Drop for Stack { -/// fn drop(&mut self) { -/// unsafe { -/// // Unprotected load. -/// let mut node = self.head.load(Relaxed, epoch::unprotected()); -/// -/// while let Some(n) = node.as_ref() { -/// // Unprotected load. -/// let next = n.next.load(Relaxed, epoch::unprotected()); -/// -/// // Take ownership of the node, then drop its data and deallocate it. -/// let mut o = node.into_owned(); -/// ManuallyDrop::drop(&mut o.data); -/// drop(o); -/// -/// node = next; -/// } -/// } -/// } -/// } -/// ``` -/// -/// [`Atomic`]: super::Atomic -/// [`defer`]: Guard::defer -#[inline] -pub unsafe fn unprotected() -> &'static Guard { - // An unprotected guard is just a `Guard` with its field `local` set to null. - // We make a newtype over `Guard` because `Guard` isn't `Sync`, so can't be directly stored in - // a `static` - struct GuardWrapper(Guard); - unsafe impl Sync for GuardWrapper {} - static UNPROTECTED: GuardWrapper = GuardWrapper(Guard { - local: core::ptr::null(), - }); - &UNPROTECTED.0 -} diff --git a/third-party/vendor/crossbeam-epoch/src/internal.rs b/third-party/vendor/crossbeam-epoch/src/internal.rs deleted file mode 100644 index b2e9e71b..00000000 --- a/third-party/vendor/crossbeam-epoch/src/internal.rs +++ /dev/null @@ -1,600 +0,0 @@ -//! The global data and participant for garbage collection. -//! -//! # Registration -//! -//! In order to track all participants in one place, we need some form of participant -//! registration. When a participant is created, it is registered to a global lock-free -//! singly-linked list of registries; and when a participant is leaving, it is unregistered from the -//! list. -//! -//! # Pinning -//! -//! Every participant contains an integer that tells whether the participant is pinned and if so, -//! what was the global epoch at the time it was pinned. Participants also hold a pin counter that -//! aids in periodic global epoch advancement. -//! -//! When a participant is pinned, a `Guard` is returned as a witness that the participant is pinned. -//! Guards are necessary for performing atomic operations, and for freeing/dropping locations. -//! -//! # Thread-local bag -//! -//! Objects that get unlinked from concurrent data structures must be stashed away until the global -//! epoch sufficiently advances so that they become safe for destruction. Pointers to such objects -//! are pushed into a thread-local bag, and when it becomes full, the bag is marked with the current -//! global epoch and pushed into the global queue of bags. We store objects in thread-local storages -//! for amortizing the synchronization cost of pushing the garbages to a global queue. -//! -//! # Global queue -//! -//! Whenever a bag is pushed into a queue, the objects in some bags in the queue are collected and -//! destroyed along the way. This design reduces contention on data structures. The global queue -//! cannot be explicitly accessed: the only way to interact with it is by calling functions -//! `defer()` that adds an object to the thread-local bag, or `collect()` that manually triggers -//! garbage collection. -//! -//! Ideally each instance of concurrent data structure may have its own queue that gets fully -//! destroyed as soon as the data structure gets dropped. - -use crate::primitive::cell::UnsafeCell; -use crate::primitive::sync::atomic::{self, Ordering}; -use core::cell::Cell; -use core::mem::{self, ManuallyDrop}; -use core::num::Wrapping; -use core::{fmt, ptr}; - -use crossbeam_utils::CachePadded; - -use crate::atomic::{Owned, Shared}; -use crate::collector::{Collector, LocalHandle}; -use crate::deferred::Deferred; -use crate::epoch::{AtomicEpoch, Epoch}; -use crate::guard::{unprotected, Guard}; -use crate::sync::list::{Entry, IsElement, IterError, List}; -use crate::sync::queue::Queue; - -/// Maximum number of objects a bag can contain. -#[cfg(not(any(crossbeam_sanitize, miri)))] -const MAX_OBJECTS: usize = 64; -// Makes it more likely to trigger any potential data races. -#[cfg(any(crossbeam_sanitize, miri))] -const MAX_OBJECTS: usize = 4; - -/// A bag of deferred functions. -pub(crate) struct Bag { - /// Stashed objects. - deferreds: [Deferred; MAX_OBJECTS], - len: usize, -} - -/// `Bag::try_push()` requires that it is safe for another thread to execute the given functions. -unsafe impl Send for Bag {} - -impl Bag { - /// Returns a new, empty bag. - pub(crate) fn new() -> Self { - Self::default() - } - - /// Returns `true` if the bag is empty. - pub(crate) fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Attempts to insert a deferred function into the bag. - /// - /// Returns `Ok(())` if successful, and `Err(deferred)` for the given `deferred` if the bag is - /// full. - /// - /// # Safety - /// - /// It should be safe for another thread to execute the given function. - pub(crate) unsafe fn try_push(&mut self, deferred: Deferred) -> Result<(), Deferred> { - if self.len < MAX_OBJECTS { - self.deferreds[self.len] = deferred; - self.len += 1; - Ok(()) - } else { - Err(deferred) - } - } - - /// Seals the bag with the given epoch. - fn seal(self, epoch: Epoch) -> SealedBag { - SealedBag { epoch, _bag: self } - } -} - -impl Default for Bag { - fn default() -> Self { - Bag { - len: 0, - deferreds: [Deferred::NO_OP; MAX_OBJECTS], - } - } -} - -impl Drop for Bag { - fn drop(&mut self) { - // Call all deferred functions. - for deferred in &mut self.deferreds[..self.len] { - let no_op = Deferred::NO_OP; - let owned_deferred = mem::replace(deferred, no_op); - owned_deferred.call(); - } - } -} - -// can't #[derive(Debug)] because Debug is not implemented for arrays 64 items long -impl fmt::Debug for Bag { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Bag") - .field("deferreds", &&self.deferreds[..self.len]) - .finish() - } -} - -/// A pair of an epoch and a bag. -#[derive(Default, Debug)] -struct SealedBag { - epoch: Epoch, - _bag: Bag, -} - -/// It is safe to share `SealedBag` because `is_expired` only inspects the epoch. -unsafe impl Sync for SealedBag {} - -impl SealedBag { - /// Checks if it is safe to drop the bag w.r.t. the given global epoch. - fn is_expired(&self, global_epoch: Epoch) -> bool { - // A pinned participant can witness at most one epoch advancement. Therefore, any bag that - // is within one epoch of the current one cannot be destroyed yet. - global_epoch.wrapping_sub(self.epoch) >= 2 - } -} - -/// The global data for a garbage collector. -pub(crate) struct Global { - /// The intrusive linked list of `Local`s. - locals: List, - - /// The global queue of bags of deferred functions. - queue: Queue, - - /// The global epoch. - pub(crate) epoch: CachePadded, -} - -impl Global { - /// Number of bags to destroy. - const COLLECT_STEPS: usize = 8; - - /// Creates a new global data for garbage collection. - #[inline] - pub(crate) fn new() -> Self { - Self { - locals: List::new(), - queue: Queue::new(), - epoch: CachePadded::new(AtomicEpoch::new(Epoch::starting())), - } - } - - /// Pushes the bag into the global queue and replaces the bag with a new empty bag. - pub(crate) fn push_bag(&self, bag: &mut Bag, guard: &Guard) { - let bag = mem::replace(bag, Bag::new()); - - atomic::fence(Ordering::SeqCst); - - let epoch = self.epoch.load(Ordering::Relaxed); - self.queue.push(bag.seal(epoch), guard); - } - - /// Collects several bags from the global queue and executes deferred functions in them. - /// - /// Note: This may itself produce garbage and in turn allocate new bags. - /// - /// `pin()` rarely calls `collect()`, so we want the compiler to place that call on a cold - /// path. In other words, we want the compiler to optimize branching for the case when - /// `collect()` is not called. - #[cold] - pub(crate) fn collect(&self, guard: &Guard) { - let global_epoch = self.try_advance(guard); - - let steps = if cfg!(crossbeam_sanitize) { - usize::max_value() - } else { - Self::COLLECT_STEPS - }; - - for _ in 0..steps { - match self.queue.try_pop_if( - &|sealed_bag: &SealedBag| sealed_bag.is_expired(global_epoch), - guard, - ) { - None => break, - Some(sealed_bag) => drop(sealed_bag), - } - } - } - - /// Attempts to advance the global epoch. - /// - /// The global epoch can advance only if all currently pinned participants have been pinned in - /// the current epoch. - /// - /// Returns the current global epoch. - /// - /// `try_advance()` is annotated `#[cold]` because it is rarely called. - #[cold] - pub(crate) fn try_advance(&self, guard: &Guard) -> Epoch { - let global_epoch = self.epoch.load(Ordering::Relaxed); - atomic::fence(Ordering::SeqCst); - - // TODO(stjepang): `Local`s are stored in a linked list because linked lists are fairly - // easy to implement in a lock-free manner. However, traversal can be slow due to cache - // misses and data dependencies. We should experiment with other data structures as well. - for local in self.locals.iter(guard) { - match local { - Err(IterError::Stalled) => { - // A concurrent thread stalled this iteration. That thread might also try to - // advance the epoch, in which case we leave the job to it. Otherwise, the - // epoch will not be advanced. - return global_epoch; - } - Ok(local) => { - let local_epoch = local.epoch.load(Ordering::Relaxed); - - // If the participant was pinned in a different epoch, we cannot advance the - // global epoch just yet. - if local_epoch.is_pinned() && local_epoch.unpinned() != global_epoch { - return global_epoch; - } - } - } - } - atomic::fence(Ordering::Acquire); - - // All pinned participants were pinned in the current global epoch. - // Now let's advance the global epoch... - // - // Note that if another thread already advanced it before us, this store will simply - // overwrite the global epoch with the same value. This is true because `try_advance` was - // called from a thread that was pinned in `global_epoch`, and the global epoch cannot be - // advanced two steps ahead of it. - let new_epoch = global_epoch.successor(); - self.epoch.store(new_epoch, Ordering::Release); - new_epoch - } -} - -/// Participant for garbage collection. -#[repr(C)] // Note: `entry` must be the first field -pub(crate) struct Local { - /// A node in the intrusive linked list of `Local`s. - entry: Entry, - - /// A reference to the global data. - /// - /// When all guards and handles get dropped, this reference is destroyed. - collector: UnsafeCell>, - - /// The local bag of deferred functions. - pub(crate) bag: UnsafeCell, - - /// The number of guards keeping this participant pinned. - guard_count: Cell, - - /// The number of active handles. - handle_count: Cell, - - /// Total number of pinnings performed. - /// - /// This is just an auxiliary counter that sometimes kicks off collection. - pin_count: Cell>, - - /// The local epoch. - epoch: CachePadded, -} - -// Make sure `Local` is less than or equal to 2048 bytes. -// https://github.com/crossbeam-rs/crossbeam/issues/551 -#[cfg(not(any(crossbeam_sanitize, miri)))] // `crossbeam_sanitize` and `miri` reduce the size of `Local` -#[test] -fn local_size() { - // TODO: https://github.com/crossbeam-rs/crossbeam/issues/869 - // assert!( - // core::mem::size_of::() <= 2048, - // "An allocation of `Local` should be <= 2048 bytes." - // ); -} - -impl Local { - /// Number of pinnings after which a participant will execute some deferred functions from the - /// global queue. - const PINNINGS_BETWEEN_COLLECT: usize = 128; - - /// Registers a new `Local` in the provided `Global`. - pub(crate) fn register(collector: &Collector) -> LocalHandle { - unsafe { - // Since we dereference no pointers in this block, it is safe to use `unprotected`. - - let local = Owned::new(Local { - entry: Entry::default(), - collector: UnsafeCell::new(ManuallyDrop::new(collector.clone())), - bag: UnsafeCell::new(Bag::new()), - guard_count: Cell::new(0), - handle_count: Cell::new(1), - pin_count: Cell::new(Wrapping(0)), - epoch: CachePadded::new(AtomicEpoch::new(Epoch::starting())), - }) - .into_shared(unprotected()); - collector.global.locals.insert(local, unprotected()); - LocalHandle { - local: local.as_raw(), - } - } - } - - /// Returns a reference to the `Global` in which this `Local` resides. - #[inline] - pub(crate) fn global(&self) -> &Global { - &self.collector().global - } - - /// Returns a reference to the `Collector` in which this `Local` resides. - #[inline] - pub(crate) fn collector(&self) -> &Collector { - self.collector.with(|c| unsafe { &**c }) - } - - /// Returns `true` if the current participant is pinned. - #[inline] - pub(crate) fn is_pinned(&self) -> bool { - self.guard_count.get() > 0 - } - - /// Adds `deferred` to the thread-local bag. - /// - /// # Safety - /// - /// It should be safe for another thread to execute the given function. - pub(crate) unsafe fn defer(&self, mut deferred: Deferred, guard: &Guard) { - let bag = self.bag.with_mut(|b| &mut *b); - - while let Err(d) = bag.try_push(deferred) { - self.global().push_bag(bag, guard); - deferred = d; - } - } - - pub(crate) fn flush(&self, guard: &Guard) { - let bag = self.bag.with_mut(|b| unsafe { &mut *b }); - - if !bag.is_empty() { - self.global().push_bag(bag, guard); - } - - self.global().collect(guard); - } - - /// Pins the `Local`. - #[inline] - pub(crate) fn pin(&self) -> Guard { - let guard = Guard { local: self }; - - let guard_count = self.guard_count.get(); - self.guard_count.set(guard_count.checked_add(1).unwrap()); - - if guard_count == 0 { - let global_epoch = self.global().epoch.load(Ordering::Relaxed); - let new_epoch = global_epoch.pinned(); - - // Now we must store `new_epoch` into `self.epoch` and execute a `SeqCst` fence. - // The fence makes sure that any future loads from `Atomic`s will not happen before - // this store. - if cfg!(all( - any(target_arch = "x86", target_arch = "x86_64"), - not(miri) - )) { - // HACK(stjepang): On x86 architectures there are two different ways of executing - // a `SeqCst` fence. - // - // 1. `atomic::fence(SeqCst)`, which compiles into a `mfence` instruction. - // 2. `_.compare_exchange(_, _, SeqCst, SeqCst)`, which compiles into a `lock cmpxchg` - // instruction. - // - // Both instructions have the effect of a full barrier, but benchmarks have shown - // that the second one makes pinning faster in this particular case. It is not - // clear that this is permitted by the C++ memory model (SC fences work very - // differently from SC accesses), but experimental evidence suggests that this - // works fine. Using inline assembly would be a viable (and correct) alternative, - // but alas, that is not possible on stable Rust. - let current = Epoch::starting(); - let res = self.epoch.compare_exchange( - current, - new_epoch, - Ordering::SeqCst, - Ordering::SeqCst, - ); - debug_assert!(res.is_ok(), "participant was expected to be unpinned"); - // We add a compiler fence to make it less likely for LLVM to do something wrong - // here. Formally, this is not enough to get rid of data races; practically, - // it should go a long way. - atomic::compiler_fence(Ordering::SeqCst); - } else { - self.epoch.store(new_epoch, Ordering::Relaxed); - atomic::fence(Ordering::SeqCst); - } - - // Increment the pin counter. - let count = self.pin_count.get(); - self.pin_count.set(count + Wrapping(1)); - - // After every `PINNINGS_BETWEEN_COLLECT` try advancing the epoch and collecting - // some garbage. - if count.0 % Self::PINNINGS_BETWEEN_COLLECT == 0 { - self.global().collect(&guard); - } - } - - guard - } - - /// Unpins the `Local`. - #[inline] - pub(crate) fn unpin(&self) { - let guard_count = self.guard_count.get(); - self.guard_count.set(guard_count - 1); - - if guard_count == 1 { - self.epoch.store(Epoch::starting(), Ordering::Release); - - if self.handle_count.get() == 0 { - self.finalize(); - } - } - } - - /// Unpins and then pins the `Local`. - #[inline] - pub(crate) fn repin(&self) { - let guard_count = self.guard_count.get(); - - // Update the local epoch only if there's only one guard. - if guard_count == 1 { - let epoch = self.epoch.load(Ordering::Relaxed); - let global_epoch = self.global().epoch.load(Ordering::Relaxed).pinned(); - - // Update the local epoch only if the global epoch is greater than the local epoch. - if epoch != global_epoch { - // We store the new epoch with `Release` because we need to ensure any memory - // accesses from the previous epoch do not leak into the new one. - self.epoch.store(global_epoch, Ordering::Release); - - // However, we don't need a following `SeqCst` fence, because it is safe for memory - // accesses from the new epoch to be executed before updating the local epoch. At - // worse, other threads will see the new epoch late and delay GC slightly. - } - } - } - - /// Increments the handle count. - #[inline] - pub(crate) fn acquire_handle(&self) { - let handle_count = self.handle_count.get(); - debug_assert!(handle_count >= 1); - self.handle_count.set(handle_count + 1); - } - - /// Decrements the handle count. - #[inline] - pub(crate) fn release_handle(&self) { - let guard_count = self.guard_count.get(); - let handle_count = self.handle_count.get(); - debug_assert!(handle_count >= 1); - self.handle_count.set(handle_count - 1); - - if guard_count == 0 && handle_count == 1 { - self.finalize(); - } - } - - /// Removes the `Local` from the global linked list. - #[cold] - fn finalize(&self) { - debug_assert_eq!(self.guard_count.get(), 0); - debug_assert_eq!(self.handle_count.get(), 0); - - // Temporarily increment handle count. This is required so that the following call to `pin` - // doesn't call `finalize` again. - self.handle_count.set(1); - unsafe { - // Pin and move the local bag into the global queue. It's important that `push_bag` - // doesn't defer destruction on any new garbage. - let guard = &self.pin(); - self.global() - .push_bag(self.bag.with_mut(|b| &mut *b), guard); - } - // Revert the handle count back to zero. - self.handle_count.set(0); - - unsafe { - // Take the reference to the `Global` out of this `Local`. Since we're not protected - // by a guard at this time, it's crucial that the reference is read before marking the - // `Local` as deleted. - let collector: Collector = ptr::read(self.collector.with(|c| &*(*c))); - - // Mark this node in the linked list as deleted. - self.entry.delete(unprotected()); - - // Finally, drop the reference to the global. Note that this might be the last reference - // to the `Global`. If so, the global data will be destroyed and all deferred functions - // in its queue will be executed. - drop(collector); - } - } -} - -impl IsElement for Local { - fn entry_of(local: &Self) -> &Entry { - // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it. - unsafe { - let entry_ptr = (local as *const Self).cast::(); - &*entry_ptr - } - } - - unsafe fn element_of(entry: &Entry) -> &Self { - // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it. - let local_ptr = (entry as *const Entry).cast::(); - &*local_ptr - } - - unsafe fn finalize(entry: &Entry, guard: &Guard) { - guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _)); - } -} - -#[cfg(all(test, not(crossbeam_loom)))] -mod tests { - use std::sync::atomic::{AtomicUsize, Ordering}; - - use super::*; - - #[test] - fn check_defer() { - static FLAG: AtomicUsize = AtomicUsize::new(0); - fn set() { - FLAG.store(42, Ordering::Relaxed); - } - - let d = Deferred::new(set); - assert_eq!(FLAG.load(Ordering::Relaxed), 0); - d.call(); - assert_eq!(FLAG.load(Ordering::Relaxed), 42); - } - - #[test] - fn check_bag() { - static FLAG: AtomicUsize = AtomicUsize::new(0); - fn incr() { - FLAG.fetch_add(1, Ordering::Relaxed); - } - - let mut bag = Bag::new(); - assert!(bag.is_empty()); - - for _ in 0..MAX_OBJECTS { - assert!(unsafe { bag.try_push(Deferred::new(incr)).is_ok() }); - assert!(!bag.is_empty()); - assert_eq!(FLAG.load(Ordering::Relaxed), 0); - } - - let result = unsafe { bag.try_push(Deferred::new(incr)) }; - assert!(result.is_err()); - assert!(!bag.is_empty()); - assert_eq!(FLAG.load(Ordering::Relaxed), 0); - - drop(bag); - assert_eq!(FLAG.load(Ordering::Relaxed), MAX_OBJECTS); - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/lib.rs b/third-party/vendor/crossbeam-epoch/src/lib.rs deleted file mode 100644 index fd4d74be..00000000 --- a/third-party/vendor/crossbeam-epoch/src/lib.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! Epoch-based memory reclamation. -//! -//! An interesting problem concurrent collections deal with comes from the remove operation. -//! Suppose that a thread removes an element from a lock-free map, while another thread is reading -//! that same element at the same time. The first thread must wait until the second thread stops -//! reading the element. Only then it is safe to destruct it. -//! -//! Programming languages that come with garbage collectors solve this problem trivially. The -//! garbage collector will destruct the removed element when no thread can hold a reference to it -//! anymore. -//! -//! This crate implements a basic memory reclamation mechanism, which is based on epochs. When an -//! element gets removed from a concurrent collection, it is inserted into a pile of garbage and -//! marked with the current epoch. Every time a thread accesses a collection, it checks the current -//! epoch, attempts to increment it, and destructs some garbage that became so old that no thread -//! can be referencing it anymore. -//! -//! That is the general mechanism behind epoch-based memory reclamation, but the details are a bit -//! more complicated. Anyhow, memory reclamation is designed to be fully automatic and something -//! users of concurrent collections don't have to worry much about. -//! -//! # Pointers -//! -//! Concurrent collections are built using atomic pointers. This module provides [`Atomic`], which -//! is just a shared atomic pointer to a heap-allocated object. Loading an [`Atomic`] yields a -//! [`Shared`], which is an epoch-protected pointer through which the loaded object can be safely -//! read. -//! -//! # Pinning -//! -//! Before an [`Atomic`] can be loaded, a participant must be [`pin`]ned. By pinning a participant -//! we declare that any object that gets removed from now on must not be destructed just -//! yet. Garbage collection of newly removed objects is suspended until the participant gets -//! unpinned. -//! -//! # Garbage -//! -//! Objects that get removed from concurrent collections must be stashed away until all currently -//! pinned participants get unpinned. Such objects can be stored into a thread-local or global -//! storage, where they are kept until the right time for their destruction comes. -//! -//! There is a global shared instance of garbage queue. You can [`defer`](Guard::defer) the execution of an -//! arbitrary function until the global epoch is advanced enough. Most notably, concurrent data -//! structures may defer the deallocation of an object. -//! -//! # APIs -//! -//! For majority of use cases, just use the default garbage collector by invoking [`pin`]. If you -//! want to create your own garbage collector, use the [`Collector`] API. - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn( - missing_docs, - missing_debug_implementations, - rust_2018_idioms, - unreachable_pub -)] -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(crossbeam_loom)] -extern crate loom_crate as loom; - -#[cfg(crossbeam_loom)] -#[allow(unused_imports, dead_code)] -mod primitive { - pub(crate) mod cell { - pub(crate) use loom::cell::UnsafeCell; - } - pub(crate) mod sync { - pub(crate) mod atomic { - pub(crate) use loom::sync::atomic::{fence, AtomicPtr, AtomicUsize, Ordering}; - - // FIXME: loom does not support compiler_fence at the moment. - // https://github.com/tokio-rs/loom/issues/117 - // we use fence as a stand-in for compiler_fence for the time being. - // this may miss some races since fence is stronger than compiler_fence, - // but it's the best we can do for the time being. - pub(crate) use self::fence as compiler_fence; - } - pub(crate) use loom::sync::Arc; - } - pub(crate) use loom::thread_local; -} -#[cfg(target_has_atomic = "ptr")] -#[cfg(not(crossbeam_loom))] -#[allow(unused_imports, dead_code)] -mod primitive { - pub(crate) mod cell { - #[derive(Debug)] - #[repr(transparent)] - pub(crate) struct UnsafeCell(::core::cell::UnsafeCell); - - // loom's UnsafeCell has a slightly different API than the standard library UnsafeCell. - // Since we want the rest of the code to be agnostic to whether it's running under loom or - // not, we write this small wrapper that provides the loom-supported API for the standard - // library UnsafeCell. This is also what the loom documentation recommends: - // https://github.com/tokio-rs/loom#handling-loom-api-differences - impl UnsafeCell { - #[inline] - pub(crate) const fn new(data: T) -> UnsafeCell { - UnsafeCell(::core::cell::UnsafeCell::new(data)) - } - - #[inline] - pub(crate) fn with(&self, f: impl FnOnce(*const T) -> R) -> R { - f(self.0.get()) - } - - #[inline] - pub(crate) fn with_mut(&self, f: impl FnOnce(*mut T) -> R) -> R { - f(self.0.get()) - } - } - } - pub(crate) mod sync { - pub(crate) mod atomic { - pub(crate) use core::sync::atomic::{ - compiler_fence, fence, AtomicPtr, AtomicUsize, Ordering, - }; - } - #[cfg(feature = "alloc")] - pub(crate) use alloc::sync::Arc; - } - - #[cfg(feature = "std")] - pub(crate) use std::thread_local; -} - -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -extern crate alloc; - -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod atomic; -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod collector; -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod deferred; -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod epoch; -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod guard; -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod internal; -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod sync; - -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -#[allow(deprecated)] -pub use crate::atomic::{CompareAndSetError, CompareAndSetOrdering}; -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -pub use crate::{ - atomic::{Atomic, CompareExchangeError, Owned, Pointable, Pointer, Shared}, - collector::{Collector, LocalHandle}, - guard::{unprotected, Guard}, -}; - -#[cfg(feature = "std")] -mod default; -#[cfg(feature = "std")] -pub use crate::default::{default_collector, is_pinned, pin}; diff --git a/third-party/vendor/crossbeam-epoch/src/sync/list.rs b/third-party/vendor/crossbeam-epoch/src/sync/list.rs deleted file mode 100644 index 52ffd6fc..00000000 --- a/third-party/vendor/crossbeam-epoch/src/sync/list.rs +++ /dev/null @@ -1,487 +0,0 @@ -//! Lock-free intrusive linked list. -//! -//! Ideas from Michael. High Performance Dynamic Lock-Free Hash Tables and List-Based Sets. SPAA -//! 2002. - -use core::marker::PhantomData; -use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; - -use crate::{unprotected, Atomic, Guard, Shared}; - -/// An entry in a linked list. -/// -/// An Entry is accessed from multiple threads, so it would be beneficial to put it in a different -/// cache-line than thread-local data in terms of performance. -#[derive(Debug)] -pub(crate) struct Entry { - /// The next entry in the linked list. - /// If the tag is 1, this entry is marked as deleted. - next: Atomic, -} - -/// Implementing this trait asserts that the type `T` can be used as an element in the intrusive -/// linked list defined in this module. `T` has to contain (or otherwise be linked to) an instance -/// of `Entry`. -/// -/// # Example -/// -/// ```ignore -/// struct A { -/// entry: Entry, -/// data: usize, -/// } -/// -/// impl IsElement for A { -/// fn entry_of(a: &A) -> &Entry { -/// let entry_ptr = ((a as usize) + offset_of!(A, entry)) as *const Entry; -/// unsafe { &*entry_ptr } -/// } -/// -/// unsafe fn element_of(entry: &Entry) -> &T { -/// let elem_ptr = ((entry as usize) - offset_of!(A, entry)) as *const T; -/// &*elem_ptr -/// } -/// -/// unsafe fn finalize(entry: &Entry, guard: &Guard) { -/// guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _)); -/// } -/// } -/// ``` -/// -/// This trait is implemented on a type separate from `T` (although it can be just `T`), because -/// one type might be placeable into multiple lists, in which case it would require multiple -/// implementations of `IsElement`. In such cases, each struct implementing `IsElement` -/// represents a distinct `Entry` in `T`. -/// -/// For example, we can insert the following struct into two lists using `entry1` for one -/// and `entry2` for the other: -/// -/// ```ignore -/// struct B { -/// entry1: Entry, -/// entry2: Entry, -/// data: usize, -/// } -/// ``` -/// -pub(crate) trait IsElement { - /// Returns a reference to this element's `Entry`. - fn entry_of(_: &T) -> &Entry; - - /// Given a reference to an element's entry, returns that element. - /// - /// ```ignore - /// let elem = ListElement::new(); - /// assert_eq!(elem.entry_of(), - /// unsafe { ListElement::element_of(elem.entry_of()) } ); - /// ``` - /// - /// # Safety - /// - /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance - /// of the element type (`T`). - unsafe fn element_of(_: &Entry) -> &T; - - /// The function that is called when an entry is unlinked from list. - /// - /// # Safety - /// - /// The caller has to guarantee that the `Entry` is called with was retrieved from an instance - /// of the element type (`T`). - unsafe fn finalize(_: &Entry, _: &Guard); -} - -/// A lock-free, intrusive linked list of type `T`. -#[derive(Debug)] -pub(crate) struct List = T> { - /// The head of the linked list. - head: Atomic, - - /// The phantom data for using `T` and `C`. - _marker: PhantomData<(T, C)>, -} - -/// An iterator used for retrieving values from the list. -pub(crate) struct Iter<'g, T, C: IsElement> { - /// The guard that protects the iteration. - guard: &'g Guard, - - /// Pointer from the predecessor to the current entry. - pred: &'g Atomic, - - /// The current entry. - curr: Shared<'g, Entry>, - - /// The list head, needed for restarting iteration. - head: &'g Atomic, - - /// Logically, we store a borrow of an instance of `T` and - /// use the type information from `C`. - _marker: PhantomData<(&'g T, C)>, -} - -/// An error that occurs during iteration over the list. -#[derive(PartialEq, Debug)] -pub(crate) enum IterError { - /// A concurrent thread modified the state of the list at the same place that this iterator - /// was inspecting. Subsequent iteration will restart from the beginning of the list. - Stalled, -} - -impl Default for Entry { - /// Returns the empty entry. - fn default() -> Self { - Self { - next: Atomic::null(), - } - } -} - -impl Entry { - /// Marks this entry as deleted, deferring the actual deallocation to a later iteration. - /// - /// # Safety - /// - /// The entry should be a member of a linked list, and it should not have been deleted. - /// It should be safe to call `C::finalize` on the entry after the `guard` is dropped, where `C` - /// is the associated helper for the linked list. - pub(crate) unsafe fn delete(&self, guard: &Guard) { - self.next.fetch_or(1, Release, guard); - } -} - -impl> List { - /// Returns a new, empty linked list. - pub(crate) fn new() -> Self { - Self { - head: Atomic::null(), - _marker: PhantomData, - } - } - - /// Inserts `entry` into the head of the list. - /// - /// # Safety - /// - /// You should guarantee that: - /// - /// - `container` is not null - /// - `container` is immovable, e.g. inside an `Owned` - /// - the same `Entry` is not inserted more than once - /// - the inserted object will be removed before the list is dropped - pub(crate) unsafe fn insert<'g>(&'g self, container: Shared<'g, T>, guard: &'g Guard) { - // Insert right after head, i.e. at the beginning of the list. - let to = &self.head; - // Get the intrusively stored Entry of the new element to insert. - let entry: &Entry = C::entry_of(container.deref()); - // Make a Shared ptr to that Entry. - let entry_ptr = Shared::from(entry as *const _); - // Read the current successor of where we want to insert. - let mut next = to.load(Relaxed, guard); - - loop { - // Set the Entry of the to-be-inserted element to point to the previous successor of - // `to`. - entry.next.store(next, Relaxed); - match to.compare_exchange_weak(next, entry_ptr, Release, Relaxed, guard) { - Ok(_) => break, - // We lost the race or weak CAS failed spuriously. Update the successor and try - // again. - Err(err) => next = err.current, - } - } - } - - /// Returns an iterator over all objects. - /// - /// # Caveat - /// - /// Every object that is inserted at the moment this function is called and persists at least - /// until the end of iteration will be returned. Since this iterator traverses a lock-free - /// linked list that may be concurrently modified, some additional caveats apply: - /// - /// 1. If a new object is inserted during iteration, it may or may not be returned. - /// 2. If an object is deleted during iteration, it may or may not be returned. - /// 3. The iteration may be aborted when it lost in a race condition. In this case, the winning - /// thread will continue to iterate over the same list. - pub(crate) fn iter<'g>(&'g self, guard: &'g Guard) -> Iter<'g, T, C> { - Iter { - guard, - pred: &self.head, - curr: self.head.load(Acquire, guard), - head: &self.head, - _marker: PhantomData, - } - } -} - -impl> Drop for List { - fn drop(&mut self) { - unsafe { - let guard = unprotected(); - let mut curr = self.head.load(Relaxed, guard); - while let Some(c) = curr.as_ref() { - let succ = c.next.load(Relaxed, guard); - // Verify that all elements have been removed from the list. - assert_eq!(succ.tag(), 1); - - C::finalize(curr.deref(), guard); - curr = succ; - } - } - } -} - -impl<'g, T: 'g, C: IsElement> Iterator for Iter<'g, T, C> { - type Item = Result<&'g T, IterError>; - - fn next(&mut self) -> Option { - while let Some(c) = unsafe { self.curr.as_ref() } { - let succ = c.next.load(Acquire, self.guard); - - if succ.tag() == 1 { - // This entry was removed. Try unlinking it from the list. - let succ = succ.with_tag(0); - - // The tag should always be zero, because removing a node after a logically deleted - // node leaves the list in an invalid state. - debug_assert!(self.curr.tag() == 0); - - // Try to unlink `curr` from the list, and get the new value of `self.pred`. - let succ = match self - .pred - .compare_exchange(self.curr, succ, Acquire, Acquire, self.guard) - { - Ok(_) => { - // We succeeded in unlinking `curr`, so we have to schedule - // deallocation. Deferred drop is okay, because `list.delete()` can only be - // called if `T: 'static`. - unsafe { - C::finalize(self.curr.deref(), self.guard); - } - - // `succ` is the new value of `self.pred`. - succ - } - Err(e) => { - // `e.current` is the current value of `self.pred`. - e.current - } - }; - - // If the predecessor node is already marked as deleted, we need to restart from - // `head`. - if succ.tag() != 0 { - self.pred = self.head; - self.curr = self.head.load(Acquire, self.guard); - - return Some(Err(IterError::Stalled)); - } - - // Move over the removed by only advancing `curr`, not `pred`. - self.curr = succ; - continue; - } - - // Move one step forward. - self.pred = &c.next; - self.curr = succ; - - return Some(Ok(unsafe { C::element_of(c) })); - } - - // We reached the end of the list. - None - } -} - -#[cfg(all(test, not(crossbeam_loom)))] -mod tests { - use super::*; - use crate::{Collector, Owned}; - use crossbeam_utils::thread; - use std::sync::Barrier; - - impl IsElement for Entry { - fn entry_of(entry: &Entry) -> &Entry { - entry - } - - unsafe fn element_of(entry: &Entry) -> &Entry { - entry - } - - unsafe fn finalize(entry: &Entry, guard: &Guard) { - guard.defer_destroy(Shared::from(Self::element_of(entry) as *const _)); - } - } - - /// Checks whether the list retains inserted elements - /// and returns them in the correct order. - #[test] - fn insert() { - let collector = Collector::new(); - let handle = collector.register(); - let guard = handle.pin(); - - let l: List = List::new(); - - let e1 = Owned::new(Entry::default()).into_shared(&guard); - let e2 = Owned::new(Entry::default()).into_shared(&guard); - let e3 = Owned::new(Entry::default()).into_shared(&guard); - - unsafe { - l.insert(e1, &guard); - l.insert(e2, &guard); - l.insert(e3, &guard); - } - - let mut iter = l.iter(&guard); - let maybe_e3 = iter.next(); - assert!(maybe_e3.is_some()); - assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw()); - let maybe_e2 = iter.next(); - assert!(maybe_e2.is_some()); - assert!(maybe_e2.unwrap().unwrap() as *const Entry == e2.as_raw()); - let maybe_e1 = iter.next(); - assert!(maybe_e1.is_some()); - assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw()); - assert!(iter.next().is_none()); - - unsafe { - e1.as_ref().unwrap().delete(&guard); - e2.as_ref().unwrap().delete(&guard); - e3.as_ref().unwrap().delete(&guard); - } - } - - /// Checks whether elements can be removed from the list and whether - /// the correct elements are removed. - #[test] - fn delete() { - let collector = Collector::new(); - let handle = collector.register(); - let guard = handle.pin(); - - let l: List = List::new(); - - let e1 = Owned::new(Entry::default()).into_shared(&guard); - let e2 = Owned::new(Entry::default()).into_shared(&guard); - let e3 = Owned::new(Entry::default()).into_shared(&guard); - unsafe { - l.insert(e1, &guard); - l.insert(e2, &guard); - l.insert(e3, &guard); - e2.as_ref().unwrap().delete(&guard); - } - - let mut iter = l.iter(&guard); - let maybe_e3 = iter.next(); - assert!(maybe_e3.is_some()); - assert!(maybe_e3.unwrap().unwrap() as *const Entry == e3.as_raw()); - let maybe_e1 = iter.next(); - assert!(maybe_e1.is_some()); - assert!(maybe_e1.unwrap().unwrap() as *const Entry == e1.as_raw()); - assert!(iter.next().is_none()); - - unsafe { - e1.as_ref().unwrap().delete(&guard); - e3.as_ref().unwrap().delete(&guard); - } - - let mut iter = l.iter(&guard); - assert!(iter.next().is_none()); - } - - const THREADS: usize = 8; - const ITERS: usize = 512; - - /// Contends the list on insert and delete operations to make sure they can run concurrently. - #[test] - fn insert_delete_multi() { - let collector = Collector::new(); - - let l: List = List::new(); - let b = Barrier::new(THREADS); - - thread::scope(|s| { - for _ in 0..THREADS { - s.spawn(|_| { - b.wait(); - - let handle = collector.register(); - let guard: Guard = handle.pin(); - let mut v = Vec::with_capacity(ITERS); - - for _ in 0..ITERS { - let e = Owned::new(Entry::default()).into_shared(&guard); - v.push(e); - unsafe { - l.insert(e, &guard); - } - } - - for e in v { - unsafe { - e.as_ref().unwrap().delete(&guard); - } - } - }); - } - }) - .unwrap(); - - let handle = collector.register(); - let guard = handle.pin(); - - let mut iter = l.iter(&guard); - assert!(iter.next().is_none()); - } - - /// Contends the list on iteration to make sure that it can be iterated over concurrently. - #[test] - fn iter_multi() { - let collector = Collector::new(); - - let l: List = List::new(); - let b = Barrier::new(THREADS); - - thread::scope(|s| { - for _ in 0..THREADS { - s.spawn(|_| { - b.wait(); - - let handle = collector.register(); - let guard: Guard = handle.pin(); - let mut v = Vec::with_capacity(ITERS); - - for _ in 0..ITERS { - let e = Owned::new(Entry::default()).into_shared(&guard); - v.push(e); - unsafe { - l.insert(e, &guard); - } - } - - let mut iter = l.iter(&guard); - for _ in 0..ITERS { - assert!(iter.next().is_some()); - } - - for e in v { - unsafe { - e.as_ref().unwrap().delete(&guard); - } - } - }); - } - }) - .unwrap(); - - let handle = collector.register(); - let guard = handle.pin(); - - let mut iter = l.iter(&guard); - assert!(iter.next().is_none()); - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/sync/mod.rs b/third-party/vendor/crossbeam-epoch/src/sync/mod.rs deleted file mode 100644 index 08981be2..00000000 --- a/third-party/vendor/crossbeam-epoch/src/sync/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Synchronization primitives. - -pub(crate) mod list; -#[cfg(feature = "std")] -#[cfg(not(crossbeam_loom))] -pub(crate) mod once_lock; -pub(crate) mod queue; diff --git a/third-party/vendor/crossbeam-epoch/src/sync/once_lock.rs b/third-party/vendor/crossbeam-epoch/src/sync/once_lock.rs deleted file mode 100644 index e057aca7..00000000 --- a/third-party/vendor/crossbeam-epoch/src/sync/once_lock.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Based on unstable std::sync::OnceLock. -// -// Source: https://github.com/rust-lang/rust/blob/8e9c93df464b7ada3fc7a1c8ccddd9dcb24ee0a0/library/std/src/sync/once_lock.rs - -use core::cell::UnsafeCell; -use core::mem::MaybeUninit; -use std::sync::Once; - -pub(crate) struct OnceLock { - once: Once, - value: UnsafeCell>, - // Unlike std::sync::OnceLock, we don't need PhantomData here because - // we don't use #[may_dangle]. -} - -unsafe impl Sync for OnceLock {} -unsafe impl Send for OnceLock {} - -impl OnceLock { - /// Creates a new empty cell. - #[must_use] - pub(crate) const fn new() -> Self { - Self { - once: Once::new(), - value: UnsafeCell::new(MaybeUninit::uninit()), - } - } - - /// Gets the contents of the cell, initializing it with `f` if the cell - /// was empty. - /// - /// Many threads may call `get_or_init` concurrently with different - /// initializing functions, but it is guaranteed that only one function - /// will be executed. - /// - /// # Panics - /// - /// If `f` panics, the panic is propagated to the caller, and the cell - /// remains uninitialized. - /// - /// It is an error to reentrantly initialize the cell from `f`. The - /// exact outcome is unspecified. Current implementation deadlocks, but - /// this may be changed to a panic in the future. - pub(crate) fn get_or_init(&self, f: F) -> &T - where - F: FnOnce() -> T, - { - // Fast path check - if self.once.is_completed() { - // SAFETY: The inner value has been initialized - return unsafe { self.get_unchecked() }; - } - self.initialize(f); - - // SAFETY: The inner value has been initialized - unsafe { self.get_unchecked() } - } - - #[cold] - fn initialize(&self, f: F) - where - F: FnOnce() -> T, - { - let slot = self.value.get(); - - self.once.call_once(|| { - let value = f(); - unsafe { slot.write(MaybeUninit::new(value)) } - }); - } - - /// # Safety - /// - /// The value must be initialized - unsafe fn get_unchecked(&self) -> &T { - debug_assert!(self.once.is_completed()); - &*self.value.get().cast::() - } -} - -impl Drop for OnceLock { - fn drop(&mut self) { - if self.once.is_completed() { - // SAFETY: The inner value has been initialized - unsafe { (*self.value.get()).assume_init_drop() }; - } - } -} diff --git a/third-party/vendor/crossbeam-epoch/src/sync/queue.rs b/third-party/vendor/crossbeam-epoch/src/sync/queue.rs deleted file mode 100644 index 76c326be..00000000 --- a/third-party/vendor/crossbeam-epoch/src/sync/queue.rs +++ /dev/null @@ -1,468 +0,0 @@ -//! Michael-Scott lock-free queue. -//! -//! Usable with any number of producers and consumers. -//! -//! Michael and Scott. Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue -//! Algorithms. PODC 1996. -//! -//! Simon Doherty, Lindsay Groves, Victor Luchangco, and Mark Moir. 2004b. Formal Verification of a -//! Practical Lock-Free Queue Algorithm. - -use core::mem::MaybeUninit; -use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; - -use crossbeam_utils::CachePadded; - -use crate::{unprotected, Atomic, Guard, Owned, Shared}; - -// The representation here is a singly-linked list, with a sentinel node at the front. In general -// the `tail` pointer may lag behind the actual tail. Non-sentinel nodes are either all `Data` or -// all `Blocked` (requests for data from blocked threads). -#[derive(Debug)] -pub(crate) struct Queue { - head: CachePadded>>, - tail: CachePadded>>, -} - -struct Node { - /// The slot in which a value of type `T` can be stored. - /// - /// The type of `data` is `MaybeUninit` because a `Node` doesn't always contain a `T`. - /// For example, the sentinel node in a queue never contains a value: its slot is always empty. - /// Other nodes start their life with a push operation and contain a value until it gets popped - /// out. After that such empty nodes get added to the collector for destruction. - data: MaybeUninit, - - next: Atomic>, -} - -// Any particular `T` should never be accessed concurrently, so no need for `Sync`. -unsafe impl Sync for Queue {} -unsafe impl Send for Queue {} - -impl Queue { - /// Create a new, empty queue. - pub(crate) fn new() -> Queue { - let q = Queue { - head: CachePadded::new(Atomic::null()), - tail: CachePadded::new(Atomic::null()), - }; - let sentinel = Owned::new(Node { - data: MaybeUninit::uninit(), - next: Atomic::null(), - }); - unsafe { - let guard = unprotected(); - let sentinel = sentinel.into_shared(guard); - q.head.store(sentinel, Relaxed); - q.tail.store(sentinel, Relaxed); - q - } - } - - /// Attempts to atomically place `n` into the `next` pointer of `onto`, and returns `true` on - /// success. The queue's `tail` pointer may be updated. - #[inline(always)] - fn push_internal( - &self, - onto: Shared<'_, Node>, - new: Shared<'_, Node>, - guard: &Guard, - ) -> bool { - // is `onto` the actual tail? - let o = unsafe { onto.deref() }; - let next = o.next.load(Acquire, guard); - if unsafe { next.as_ref().is_some() } { - // if not, try to "help" by moving the tail pointer forward - let _ = self - .tail - .compare_exchange(onto, next, Release, Relaxed, guard); - false - } else { - // looks like the actual tail; attempt to link in `n` - let result = o - .next - .compare_exchange(Shared::null(), new, Release, Relaxed, guard) - .is_ok(); - if result { - // try to move the tail pointer forward - let _ = self - .tail - .compare_exchange(onto, new, Release, Relaxed, guard); - } - result - } - } - - /// Adds `t` to the back of the queue, possibly waking up threads blocked on `pop`. - pub(crate) fn push(&self, t: T, guard: &Guard) { - let new = Owned::new(Node { - data: MaybeUninit::new(t), - next: Atomic::null(), - }); - let new = Owned::into_shared(new, guard); - - loop { - // We push onto the tail, so we'll start optimistically by looking there first. - let tail = self.tail.load(Acquire, guard); - - // Attempt to push onto the `tail` snapshot; fails if `tail.next` has changed. - if self.push_internal(tail, new, guard) { - break; - } - } - } - - /// Attempts to pop a data node. `Ok(None)` if queue is empty; `Err(())` if lost race to pop. - #[inline(always)] - fn pop_internal(&self, guard: &Guard) -> Result, ()> { - let head = self.head.load(Acquire, guard); - let h = unsafe { head.deref() }; - let next = h.next.load(Acquire, guard); - match unsafe { next.as_ref() } { - Some(n) => unsafe { - self.head - .compare_exchange(head, next, Release, Relaxed, guard) - .map(|_| { - let tail = self.tail.load(Relaxed, guard); - // Advance the tail so that we don't retire a pointer to a reachable node. - if head == tail { - let _ = self - .tail - .compare_exchange(tail, next, Release, Relaxed, guard); - } - guard.defer_destroy(head); - Some(n.data.assume_init_read()) - }) - .map_err(|_| ()) - }, - None => Ok(None), - } - } - - /// Attempts to pop a data node, if the data satisfies the given condition. `Ok(None)` if queue - /// is empty or the data does not satisfy the condition; `Err(())` if lost race to pop. - #[inline(always)] - fn pop_if_internal(&self, condition: F, guard: &Guard) -> Result, ()> - where - T: Sync, - F: Fn(&T) -> bool, - { - let head = self.head.load(Acquire, guard); - let h = unsafe { head.deref() }; - let next = h.next.load(Acquire, guard); - match unsafe { next.as_ref() } { - Some(n) if condition(unsafe { &*n.data.as_ptr() }) => unsafe { - self.head - .compare_exchange(head, next, Release, Relaxed, guard) - .map(|_| { - let tail = self.tail.load(Relaxed, guard); - // Advance the tail so that we don't retire a pointer to a reachable node. - if head == tail { - let _ = self - .tail - .compare_exchange(tail, next, Release, Relaxed, guard); - } - guard.defer_destroy(head); - Some(n.data.assume_init_read()) - }) - .map_err(|_| ()) - }, - None | Some(_) => Ok(None), - } - } - - /// Attempts to dequeue from the front. - /// - /// Returns `None` if the queue is observed to be empty. - pub(crate) fn try_pop(&self, guard: &Guard) -> Option { - loop { - if let Ok(head) = self.pop_internal(guard) { - return head; - } - } - } - - /// Attempts to dequeue from the front, if the item satisfies the given condition. - /// - /// Returns `None` if the queue is observed to be empty, or the head does not satisfy the given - /// condition. - pub(crate) fn try_pop_if(&self, condition: F, guard: &Guard) -> Option - where - T: Sync, - F: Fn(&T) -> bool, - { - loop { - if let Ok(head) = self.pop_if_internal(&condition, guard) { - return head; - } - } - } -} - -impl Drop for Queue { - fn drop(&mut self) { - unsafe { - let guard = unprotected(); - - while self.try_pop(guard).is_some() {} - - // Destroy the remaining sentinel node. - let sentinel = self.head.load(Relaxed, guard); - drop(sentinel.into_owned()); - } - } -} - -#[cfg(all(test, not(crossbeam_loom)))] -mod test { - use super::*; - use crate::pin; - use crossbeam_utils::thread; - - struct Queue { - queue: super::Queue, - } - - impl Queue { - pub(crate) fn new() -> Queue { - Queue { - queue: super::Queue::new(), - } - } - - pub(crate) fn push(&self, t: T) { - let guard = &pin(); - self.queue.push(t, guard); - } - - pub(crate) fn is_empty(&self) -> bool { - let guard = &pin(); - let head = self.queue.head.load(Acquire, guard); - let h = unsafe { head.deref() }; - h.next.load(Acquire, guard).is_null() - } - - pub(crate) fn try_pop(&self) -> Option { - let guard = &pin(); - self.queue.try_pop(guard) - } - - pub(crate) fn pop(&self) -> T { - loop { - match self.try_pop() { - None => continue, - Some(t) => return t, - } - } - } - } - - #[cfg(miri)] - const CONC_COUNT: i64 = 1000; - #[cfg(not(miri))] - const CONC_COUNT: i64 = 1000000; - - #[test] - fn push_try_pop_1() { - let q: Queue = Queue::new(); - assert!(q.is_empty()); - q.push(37); - assert!(!q.is_empty()); - assert_eq!(q.try_pop(), Some(37)); - assert!(q.is_empty()); - } - - #[test] - fn push_try_pop_2() { - let q: Queue = Queue::new(); - assert!(q.is_empty()); - q.push(37); - q.push(48); - assert_eq!(q.try_pop(), Some(37)); - assert!(!q.is_empty()); - assert_eq!(q.try_pop(), Some(48)); - assert!(q.is_empty()); - } - - #[test] - fn push_try_pop_many_seq() { - let q: Queue = Queue::new(); - assert!(q.is_empty()); - for i in 0..200 { - q.push(i) - } - assert!(!q.is_empty()); - for i in 0..200 { - assert_eq!(q.try_pop(), Some(i)); - } - assert!(q.is_empty()); - } - - #[test] - fn push_pop_1() { - let q: Queue = Queue::new(); - assert!(q.is_empty()); - q.push(37); - assert!(!q.is_empty()); - assert_eq!(q.pop(), 37); - assert!(q.is_empty()); - } - - #[test] - fn push_pop_2() { - let q: Queue = Queue::new(); - q.push(37); - q.push(48); - assert_eq!(q.pop(), 37); - assert_eq!(q.pop(), 48); - } - - #[test] - fn push_pop_many_seq() { - let q: Queue = Queue::new(); - assert!(q.is_empty()); - for i in 0..200 { - q.push(i) - } - assert!(!q.is_empty()); - for i in 0..200 { - assert_eq!(q.pop(), i); - } - assert!(q.is_empty()); - } - - #[test] - fn push_try_pop_many_spsc() { - let q: Queue = Queue::new(); - assert!(q.is_empty()); - - thread::scope(|scope| { - scope.spawn(|_| { - let mut next = 0; - - while next < CONC_COUNT { - if let Some(elem) = q.try_pop() { - assert_eq!(elem, next); - next += 1; - } - } - }); - - for i in 0..CONC_COUNT { - q.push(i) - } - }) - .unwrap(); - } - - #[test] - fn push_try_pop_many_spmc() { - fn recv(_t: i32, q: &Queue) { - let mut cur = -1; - for _i in 0..CONC_COUNT { - if let Some(elem) = q.try_pop() { - assert!(elem > cur); - cur = elem; - - if cur == CONC_COUNT - 1 { - break; - } - } - } - } - - let q: Queue = Queue::new(); - assert!(q.is_empty()); - thread::scope(|scope| { - for i in 0..3 { - let q = &q; - scope.spawn(move |_| recv(i, q)); - } - - scope.spawn(|_| { - for i in 0..CONC_COUNT { - q.push(i); - } - }); - }) - .unwrap(); - } - - #[test] - fn push_try_pop_many_mpmc() { - enum LR { - Left(i64), - Right(i64), - } - - let q: Queue = Queue::new(); - assert!(q.is_empty()); - - thread::scope(|scope| { - for _t in 0..2 { - scope.spawn(|_| { - for i in CONC_COUNT - 1..CONC_COUNT { - q.push(LR::Left(i)) - } - }); - scope.spawn(|_| { - for i in CONC_COUNT - 1..CONC_COUNT { - q.push(LR::Right(i)) - } - }); - scope.spawn(|_| { - let mut vl = vec![]; - let mut vr = vec![]; - for _i in 0..CONC_COUNT { - match q.try_pop() { - Some(LR::Left(x)) => vl.push(x), - Some(LR::Right(x)) => vr.push(x), - _ => {} - } - } - - let mut vl2 = vl.clone(); - let mut vr2 = vr.clone(); - vl2.sort_unstable(); - vr2.sort_unstable(); - - assert_eq!(vl, vl2); - assert_eq!(vr, vr2); - }); - } - }) - .unwrap(); - } - - #[test] - fn push_pop_many_spsc() { - let q: Queue = Queue::new(); - - thread::scope(|scope| { - scope.spawn(|_| { - let mut next = 0; - while next < CONC_COUNT { - assert_eq!(q.pop(), next); - next += 1; - } - }); - - for i in 0..CONC_COUNT { - q.push(i) - } - }) - .unwrap(); - assert!(q.is_empty()); - } - - #[test] - fn is_empty_dont_pop() { - let q: Queue = Queue::new(); - q.push(20); - q.push(20); - assert!(!q.is_empty()); - assert!(!q.is_empty()); - assert!(q.try_pop().is_some()); - } -} diff --git a/third-party/vendor/crossbeam-epoch/tests/loom.rs b/third-party/vendor/crossbeam-epoch/tests/loom.rs deleted file mode 100644 index 4e56acdb..00000000 --- a/third-party/vendor/crossbeam-epoch/tests/loom.rs +++ /dev/null @@ -1,157 +0,0 @@ -#![cfg(crossbeam_loom)] - -use crossbeam_epoch as epoch; -use loom_crate as loom; - -use epoch::*; -use epoch::{Atomic, Owned}; -use loom::sync::atomic::Ordering::{self, Acquire, Relaxed, Release}; -use loom::sync::Arc; -use loom::thread::spawn; -use std::mem::ManuallyDrop; -use std::ptr; - -#[test] -fn it_works() { - loom::model(|| { - let collector = Collector::new(); - let item: Atomic = Atomic::from(Owned::new(String::from("boom"))); - let item2 = item.clone(); - let collector2 = collector.clone(); - let guard = collector.register().pin(); - - let jh = loom::thread::spawn(move || { - let guard = collector2.register().pin(); - guard.defer(move || { - // this isn't really safe, since other threads may still have pointers to the - // value, but in this limited test scenario it's okay, since we know the test won't - // access item after all the pins are released. - let mut item = unsafe { item2.into_owned() }; - // mutate it as a second measure to make sure the assert_eq below would fail - item.retain(|c| c == 'o'); - drop(item); - }); - }); - - let item = item.load(Ordering::SeqCst, &guard); - // we pinned strictly before the call to defer_destroy, - // so item cannot have been dropped yet - assert_eq!(*unsafe { item.deref() }, "boom"); - drop(guard); - - jh.join().unwrap(); - - drop(collector); - }) -} - -#[test] -fn treiber_stack() { - /// Treiber's lock-free stack. - /// - /// Usable with any number of producers and consumers. - #[derive(Debug)] - pub struct TreiberStack { - head: Atomic>, - } - - #[derive(Debug)] - struct Node { - data: ManuallyDrop, - next: Atomic>, - } - - impl TreiberStack { - /// Creates a new, empty stack. - pub fn new() -> TreiberStack { - TreiberStack { - head: Atomic::null(), - } - } - - /// Pushes a value on top of the stack. - pub fn push(&self, t: T) { - let mut n = Owned::new(Node { - data: ManuallyDrop::new(t), - next: Atomic::null(), - }); - - let guard = epoch::pin(); - - loop { - let head = self.head.load(Relaxed, &guard); - n.next.store(head, Relaxed); - - match self - .head - .compare_exchange(head, n, Release, Relaxed, &guard) - { - Ok(_) => break, - Err(e) => n = e.new, - } - } - } - - /// Attempts to pop the top element from the stack. - /// - /// Returns `None` if the stack is empty. - pub fn pop(&self) -> Option { - let guard = epoch::pin(); - loop { - let head = self.head.load(Acquire, &guard); - - match unsafe { head.as_ref() } { - Some(h) => { - let next = h.next.load(Relaxed, &guard); - - if self - .head - .compare_exchange(head, next, Relaxed, Relaxed, &guard) - .is_ok() - { - unsafe { - guard.defer_destroy(head); - return Some(ManuallyDrop::into_inner(ptr::read(&(*h).data))); - } - } - } - None => return None, - } - } - } - - /// Returns `true` if the stack is empty. - pub fn is_empty(&self) -> bool { - let guard = epoch::pin(); - self.head.load(Acquire, &guard).is_null() - } - } - - impl Drop for TreiberStack { - fn drop(&mut self) { - while self.pop().is_some() {} - } - } - - loom::model(|| { - let stack1 = Arc::new(TreiberStack::new()); - let stack2 = Arc::clone(&stack1); - - // use 5 since it's greater than the 4 used for the sanitize feature - let jh = spawn(move || { - for i in 0..5 { - stack2.push(i); - assert!(stack2.pop().is_some()); - } - }); - - for i in 0..5 { - stack1.push(i); - assert!(stack1.pop().is_some()); - } - - jh.join().unwrap(); - assert!(stack1.pop().is_none()); - assert!(stack1.is_empty()); - }); -} diff --git a/third-party/vendor/crossbeam-queue/.cargo-checksum.json b/third-party/vendor/crossbeam-queue/.cargo-checksum.json deleted file mode 100644 index 7203b0e2..00000000 --- a/third-party/vendor/crossbeam-queue/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"2c10a9c588d28ae9edabaaf50d224d523790080cbf82783143e170395aed2a35","Cargo.toml":"8435b3df4a6f66aa2860e874b1f98f074535b6ad9b92708ed90ccb3410f7479c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"88a50c7a414f6d8431061f0741dc6b46db012ec338b4e57d5d3e9746eeaaa543","src/array_queue.rs":"9c3360280522ae0ea3640bf8a3e454038860a6891a5fa11ef6c0237a45fb2963","src/lib.rs":"87d7a57fab9f20e088bb0612b10ee9499c2512d714b5453ab34c0400a3243ea0","src/seg_queue.rs":"f97a024d8f2a4dad332b5ff371c81a1b3750caf25cc67ae5d61ee789509b55b1","tests/array_queue.rs":"426dd0ff6698bd63108b3a567703ec2e635bce0f337134116e237b11925a7716","tests/seg_queue.rs":"7abb1008638a947440b201e1ad15f273020730715fae1f876407f1b967ae28ff"},"package":"df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"} \ No newline at end of file diff --git a/third-party/vendor/crossbeam-queue/CHANGELOG.md b/third-party/vendor/crossbeam-queue/CHANGELOG.md deleted file mode 100644 index 68c9bbd7..00000000 --- a/third-party/vendor/crossbeam-queue/CHANGELOG.md +++ /dev/null @@ -1,84 +0,0 @@ -# Version 0.3.11 - -- Remove dependency on `cfg-if`. (#1072) - -# Version 0.3.10 - -- Relax the minimum supported Rust version to 1.60. (#1056) -- Implement `UnwindSafe` and `RefUnwindSafe` for `ArrayQueue` and `SegQueue`. (#1053) -- Optimize `Drop` implementation of `ArrayQueue`. (#1057) - -# Version 0.3.9 - -- Bump the minimum supported Rust version to 1.61. (#1037) -- Improve support for targets without atomic CAS. (#1037) -- Remove build script. (#1037) - -# Version 0.3.8 - -- Fix build script bug introduced in 0.3.7. (#932) - -# Version 0.3.7 - -**Note:** This release has been yanked due to regression fixed in 0.3.8. - -- Improve support for custom targets. (#922) - -# Version 0.3.6 - -- Bump the minimum supported Rust version to 1.38. (#877) - -# Version 0.3.5 - -- Add `ArrayQueue::force_push`. (#789) - -# Version 0.3.4 - -- Implement `IntoIterator` for `ArrayQueue` and `SegQueue`. (#772) - -# Version 0.3.3 - -- Fix stacked borrows violation in `ArrayQueue` when `-Zmiri-tag-raw-pointers` is enabled. (#763) - -# Version 0.3.2 - -- Support targets that do not have atomic CAS on stable Rust. (#698) - -# Version 0.3.1 - -- Make `SegQueue::new` const fn. (#584) -- Change license to "MIT OR Apache-2.0". - -# Version 0.3.0 - -- Bump the minimum supported Rust version to 1.36. -- Remove `PushError` and `PopError`. - -# Version 0.2.3 - -- Fix bug in release (yanking 0.2.2) - -# Version 0.2.2 - -- Fix unsoundness issues by adopting `MaybeUninit`. (#458) - -# Version 0.2.1 - -- Add `no_std` support. - -# Version 0.2.0 - -- Bump the minimum required version to 1.28. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.1.2 - -- Update `crossbeam-utils` to `0.6.5`. - -# Version 0.1.1 - -- Update `crossbeam-utils` to `0.6.4`. - -# Version 0.1.0 - -- Initial version with `ArrayQueue` and `SegQueue`. diff --git a/third-party/vendor/crossbeam-queue/Cargo.toml b/third-party/vendor/crossbeam-queue/Cargo.toml deleted file mode 100644 index 6853e32e..00000000 --- a/third-party/vendor/crossbeam-queue/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.60" -name = "crossbeam-queue" -version = "0.3.11" -description = "Concurrent queues" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue" -readme = "README.md" -keywords = [ - "queue", - "mpmc", - "lock-free", - "producer", - "consumer", -] -categories = [ - "concurrency", - "data-structures", - "no-std", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/crossbeam-rs/crossbeam" - -[dependencies.crossbeam-utils] -version = "0.8.18" -default-features = false - -[dev-dependencies.rand] -version = "0.8" - -[features] -alloc = [] -default = ["std"] -nightly = ["crossbeam-utils/nightly"] -std = [ - "alloc", - "crossbeam-utils/std", -] diff --git a/third-party/vendor/crossbeam-queue/LICENSE-APACHE b/third-party/vendor/crossbeam-queue/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/third-party/vendor/crossbeam-queue/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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/third-party/vendor/crossbeam-queue/LICENSE-MIT b/third-party/vendor/crossbeam-queue/LICENSE-MIT deleted file mode 100644 index 068d491f..00000000 --- a/third-party/vendor/crossbeam-queue/LICENSE-MIT +++ /dev/null @@ -1,27 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2019 The Crossbeam Project Developers - -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/third-party/vendor/crossbeam-queue/README.md b/third-party/vendor/crossbeam-queue/README.md deleted file mode 100644 index 90267908..00000000 --- a/third-party/vendor/crossbeam-queue/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Crossbeam Queue - -[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( -https://github.com/crossbeam-rs/crossbeam/actions) -[![License](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue#license) -[![Cargo](https://img.shields.io/crates/v/crossbeam-queue.svg)]( -https://crates.io/crates/crossbeam-queue) -[![Documentation](https://docs.rs/crossbeam-queue/badge.svg)]( -https://docs.rs/crossbeam-queue) -[![Rust 1.60+](https://img.shields.io/badge/rust-1.60+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) - -This crate provides concurrent queues that can be shared among threads: - -* [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -* [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. - -Everything in this crate can be used in `no_std` environments, provided that `alloc` feature is -enabled. - -[`ArrayQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.ArrayQueue.html -[`SegQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.SegQueue.html - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam-queue = "0.3" -``` - -## Compatibility - -Crossbeam Queue supports stable Rust releases going back at least six months, -and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.60. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/third-party/vendor/crossbeam-queue/src/array_queue.rs b/third-party/vendor/crossbeam-queue/src/array_queue.rs deleted file mode 100644 index 3f6d1953..00000000 --- a/third-party/vendor/crossbeam-queue/src/array_queue.rs +++ /dev/null @@ -1,541 +0,0 @@ -//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. -//! -//! Source: -//! - - -use alloc::boxed::Box; -use core::cell::UnsafeCell; -use core::fmt; -use core::mem::{self, MaybeUninit}; -use core::panic::{RefUnwindSafe, UnwindSafe}; -use core::sync::atomic::{self, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -/// A slot in a queue. -struct Slot { - /// The current stamp. - /// - /// If the stamp equals the tail, this node will be next written to. If it equals head + 1, - /// this node will be next read from. - stamp: AtomicUsize, - - /// The value in this slot. - value: UnsafeCell>, -} - -/// A bounded multi-producer multi-consumer queue. -/// -/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed -/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an -/// element into a full queue will fail. Alternatively, [`force_push`] makes it possible for -/// this queue to be used as a ring-buffer. Having a buffer allocated upfront makes this queue -/// a bit faster than [`SegQueue`]. -/// -/// [`force_push`]: ArrayQueue::force_push -/// [`SegQueue`]: super::SegQueue -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::ArrayQueue; -/// -/// let q = ArrayQueue::new(2); -/// -/// assert_eq!(q.push('a'), Ok(())); -/// assert_eq!(q.push('b'), Ok(())); -/// assert_eq!(q.push('c'), Err('c')); -/// assert_eq!(q.pop(), Some('a')); -/// ``` -pub struct ArrayQueue { - /// The head of the queue. - /// - /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a - /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. - /// - /// Elements are popped from the head of the queue. - head: CachePadded, - - /// The tail of the queue. - /// - /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a - /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. - /// - /// Elements are pushed into the tail of the queue. - tail: CachePadded, - - /// The buffer holding slots. - buffer: Box<[Slot]>, - - /// The queue capacity. - cap: usize, - - /// A stamp with the value of `{ lap: 1, index: 0 }`. - one_lap: usize, -} - -unsafe impl Sync for ArrayQueue {} -unsafe impl Send for ArrayQueue {} - -impl UnwindSafe for ArrayQueue {} -impl RefUnwindSafe for ArrayQueue {} - -impl ArrayQueue { - /// Creates a new bounded queue with the given capacity. - /// - /// # Panics - /// - /// Panics if the capacity is zero. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::::new(100); - /// ``` - pub fn new(cap: usize) -> ArrayQueue { - assert!(cap > 0, "capacity must be non-zero"); - - // Head is initialized to `{ lap: 0, index: 0 }`. - // Tail is initialized to `{ lap: 0, index: 0 }`. - let head = 0; - let tail = 0; - - // Allocate a buffer of `cap` slots initialized - // with stamps. - let buffer: Box<[Slot]> = (0..cap) - .map(|i| { - // Set the stamp to `{ lap: 0, index: i }`. - Slot { - stamp: AtomicUsize::new(i), - value: UnsafeCell::new(MaybeUninit::uninit()), - } - }) - .collect(); - - // One lap is the smallest power of two greater than `cap`. - let one_lap = (cap + 1).next_power_of_two(); - - ArrayQueue { - buffer, - cap, - one_lap, - head: CachePadded::new(AtomicUsize::new(head)), - tail: CachePadded::new(AtomicUsize::new(tail)), - } - } - - fn push_or_else(&self, mut value: T, f: F) -> Result<(), T> - where - F: Fn(T, usize, usize, &Slot) -> Result, - { - let backoff = Backoff::new(); - let mut tail = self.tail.load(Ordering::Relaxed); - - loop { - // Deconstruct the tail. - let index = tail & (self.one_lap - 1); - let lap = tail & !(self.one_lap - 1); - - let new_tail = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - tail + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(self.one_lap) - }; - - // Inspect the corresponding slot. - debug_assert!(index < self.buffer.len()); - let slot = unsafe { self.buffer.get_unchecked(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the tail and the stamp match, we may attempt to push. - if tail == stamp { - // Try moving the tail. - match self.tail.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Relaxed, - ) { - Ok(_) => { - // Write the value into the slot and update the stamp. - unsafe { - slot.value.get().write(MaybeUninit::new(value)); - } - slot.stamp.store(tail + 1, Ordering::Release); - return Ok(()); - } - Err(t) => { - tail = t; - backoff.spin(); - } - } - } else if stamp.wrapping_add(self.one_lap) == tail + 1 { - atomic::fence(Ordering::SeqCst); - value = f(value, tail, new_tail, slot)?; - backoff.spin(); - tail = self.tail.load(Ordering::Relaxed); - } else { - // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); - tail = self.tail.load(Ordering::Relaxed); - } - } - } - - /// Attempts to push an element into the queue. - /// - /// If the queue is full, the element is returned back as an error. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert_eq!(q.push(10), Ok(())); - /// assert_eq!(q.push(20), Err(20)); - /// ``` - pub fn push(&self, value: T) -> Result<(), T> { - self.push_or_else(value, |v, tail, _, _| { - let head = self.head.load(Ordering::Relaxed); - - // If the head lags one lap behind the tail as well... - if head.wrapping_add(self.one_lap) == tail { - // ...then the queue is full. - Err(v) - } else { - Ok(v) - } - }) - } - - /// Pushes an element into the queue, replacing the oldest element if necessary. - /// - /// If the queue is full, the oldest element is replaced and returned, - /// otherwise `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(2); - /// - /// assert_eq!(q.force_push(10), None); - /// assert_eq!(q.force_push(20), None); - /// assert_eq!(q.force_push(30), Some(10)); - /// assert_eq!(q.pop(), Some(20)); - /// ``` - pub fn force_push(&self, value: T) -> Option { - self.push_or_else(value, |v, tail, new_tail, slot| { - let head = tail.wrapping_sub(self.one_lap); - let new_head = new_tail.wrapping_sub(self.one_lap); - - // Try moving the head. - if self - .head - .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Relaxed) - .is_ok() - { - // Move the tail. - self.tail.store(new_tail, Ordering::SeqCst); - - // Swap the previous value. - let old = unsafe { slot.value.get().replace(MaybeUninit::new(v)).assume_init() }; - - // Update the stamp. - slot.stamp.store(tail + 1, Ordering::Release); - - Err(old) - } else { - Ok(v) - } - }) - .err() - } - - /// Attempts to pop an element from the queue. - /// - /// If the queue is empty, `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(1); - /// assert_eq!(q.push(10), Ok(())); - /// - /// assert_eq!(q.pop(), Some(10)); - /// assert!(q.pop().is_none()); - /// ``` - pub fn pop(&self) -> Option { - let backoff = Backoff::new(); - let mut head = self.head.load(Ordering::Relaxed); - - loop { - // Deconstruct the head. - let index = head & (self.one_lap - 1); - let lap = head & !(self.one_lap - 1); - - // Inspect the corresponding slot. - debug_assert!(index < self.buffer.len()); - let slot = unsafe { self.buffer.get_unchecked(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the the stamp is ahead of the head by 1, we may attempt to pop. - if head + 1 == stamp { - let new = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - head + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(self.one_lap) - }; - - // Try moving the head. - match self.head.compare_exchange_weak( - head, - new, - Ordering::SeqCst, - Ordering::Relaxed, - ) { - Ok(_) => { - // Read the value from the slot and update the stamp. - let msg = unsafe { slot.value.get().read().assume_init() }; - slot.stamp - .store(head.wrapping_add(self.one_lap), Ordering::Release); - return Some(msg); - } - Err(h) => { - head = h; - backoff.spin(); - } - } - } else if stamp == head { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.load(Ordering::Relaxed); - - // If the tail equals the head, that means the channel is empty. - if tail == head { - return None; - } - - backoff.spin(); - head = self.head.load(Ordering::Relaxed); - } else { - // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); - head = self.head.load(Ordering::Relaxed); - } - } - } - - /// Returns the capacity of the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::::new(100); - /// - /// assert_eq!(q.capacity(), 100); - /// ``` - pub fn capacity(&self) -> usize { - self.cap - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(100); - /// - /// assert!(q.is_empty()); - /// q.push(1).unwrap(); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.load(Ordering::SeqCst); - let tail = self.tail.load(Ordering::SeqCst); - - // Is the tail lagging one lap behind head? - // Is the tail equal to the head? - // - // Note: If the head changes just before we load the tail, that means there was a moment - // when the channel was not empty, so it is safe to just return `false`. - tail == head - } - - /// Returns `true` if the queue is full. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert!(!q.is_full()); - /// q.push(1).unwrap(); - /// assert!(q.is_full()); - /// ``` - pub fn is_full(&self) -> bool { - let tail = self.tail.load(Ordering::SeqCst); - let head = self.head.load(Ordering::SeqCst); - - // Is the head lagging one lap behind tail? - // - // Note: If the tail changes just before we load the head, that means there was a moment - // when the queue was not full, so it is safe to just return `false`. - head.wrapping_add(self.one_lap) == tail - } - - /// Returns the number of elements in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::new(100); - /// assert_eq!(q.len(), 0); - /// - /// q.push(10).unwrap(); - /// assert_eq!(q.len(), 1); - /// - /// q.push(20).unwrap(); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail, then load the head. - let tail = self.tail.load(Ordering::SeqCst); - let head = self.head.load(Ordering::SeqCst); - - // If the tail didn't change, we've got consistent values to work with. - if self.tail.load(Ordering::SeqCst) == tail { - let hix = head & (self.one_lap - 1); - let tix = tail & (self.one_lap - 1); - - return if hix < tix { - tix - hix - } else if hix > tix { - self.cap - hix + tix - } else if tail == head { - 0 - } else { - self.cap - }; - } - } - } -} - -impl Drop for ArrayQueue { - fn drop(&mut self) { - if mem::needs_drop::() { - // Get the index of the head. - let head = *self.head.get_mut(); - let tail = *self.tail.get_mut(); - - let hix = head & (self.one_lap - 1); - let tix = tail & (self.one_lap - 1); - - let len = if hix < tix { - tix - hix - } else if hix > tix { - self.cap - hix + tix - } else if tail == head { - 0 - } else { - self.cap - }; - - // Loop over all slots that hold a message and drop them. - for i in 0..len { - // Compute the index of the next slot holding a message. - let index = if hix + i < self.cap { - hix + i - } else { - hix + i - self.cap - }; - - unsafe { - debug_assert!(index < self.buffer.len()); - let slot = self.buffer.get_unchecked_mut(index); - (*slot.value.get()).assume_init_drop(); - } - } - } - } -} - -impl fmt::Debug for ArrayQueue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("ArrayQueue { .. }") - } -} - -impl IntoIterator for ArrayQueue { - type Item = T; - - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter { value: self } - } -} - -#[derive(Debug)] -pub struct IntoIter { - value: ArrayQueue, -} - -impl Iterator for IntoIter { - type Item = T; - - fn next(&mut self) -> Option { - let value = &mut self.value; - let head = *value.head.get_mut(); - if value.head.get_mut() != value.tail.get_mut() { - let index = head & (value.one_lap - 1); - let lap = head & !(value.one_lap - 1); - // SAFETY: We have mutable access to this, so we can read without - // worrying about concurrency. Furthermore, we know this is - // initialized because it is the value pointed at by `value.head` - // and this is a non-empty queue. - let val = unsafe { - debug_assert!(index < value.buffer.len()); - let slot = value.buffer.get_unchecked_mut(index); - slot.value.get().read().assume_init() - }; - let new = if index + 1 < value.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - head + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(value.one_lap) - }; - *value.head.get_mut() = new; - Option::Some(val) - } else { - Option::None - } - } -} diff --git a/third-party/vendor/crossbeam-queue/src/lib.rs b/third-party/vendor/crossbeam-queue/src/lib.rs deleted file mode 100644 index 4d95f54e..00000000 --- a/third-party/vendor/crossbeam-queue/src/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Concurrent queues. -//! -//! This crate provides concurrent queues that can be shared among threads: -//! -//! * [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -//! * [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn( - missing_docs, - missing_debug_implementations, - rust_2018_idioms, - unreachable_pub -)] -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -extern crate alloc; - -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod array_queue; -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -mod seg_queue; - -#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))] -pub use crate::{array_queue::ArrayQueue, seg_queue::SegQueue}; diff --git a/third-party/vendor/crossbeam-queue/src/seg_queue.rs b/third-party/vendor/crossbeam-queue/src/seg_queue.rs deleted file mode 100644 index 973a77f8..00000000 --- a/third-party/vendor/crossbeam-queue/src/seg_queue.rs +++ /dev/null @@ -1,549 +0,0 @@ -use alloc::boxed::Box; -use core::cell::UnsafeCell; -use core::fmt; -use core::marker::PhantomData; -use core::mem::MaybeUninit; -use core::panic::{RefUnwindSafe, UnwindSafe}; -use core::ptr; -use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -// Bits indicating the state of a slot: -// * If a value has been written into the slot, `WRITE` is set. -// * If a value has been read from the slot, `READ` is set. -// * If the block is being destroyed, `DESTROY` is set. -const WRITE: usize = 1; -const READ: usize = 2; -const DESTROY: usize = 4; - -// Each block covers one "lap" of indices. -const LAP: usize = 32; -// The maximum number of values a block can hold. -const BLOCK_CAP: usize = LAP - 1; -// How many lower bits are reserved for metadata. -const SHIFT: usize = 1; -// Indicates that the block is not the last one. -const HAS_NEXT: usize = 1; - -/// A slot in a block. -struct Slot { - /// The value. - value: UnsafeCell>, - - /// The state of the slot. - state: AtomicUsize, -} - -impl Slot { - const UNINIT: Self = Self { - value: UnsafeCell::new(MaybeUninit::uninit()), - state: AtomicUsize::new(0), - }; - - /// Waits until a value is written into the slot. - fn wait_write(&self) { - let backoff = Backoff::new(); - while self.state.load(Ordering::Acquire) & WRITE == 0 { - backoff.snooze(); - } - } -} - -/// A block in a linked list. -/// -/// Each block in the list can hold up to `BLOCK_CAP` values. -struct Block { - /// The next block in the linked list. - next: AtomicPtr>, - - /// Slots for values. - slots: [Slot; BLOCK_CAP], -} - -impl Block { - /// Creates an empty block that starts at `start_index`. - fn new() -> Block { - Self { - next: AtomicPtr::new(ptr::null_mut()), - slots: [Slot::UNINIT; BLOCK_CAP], - } - } - - /// Waits until the next pointer is set. - fn wait_next(&self) -> *mut Block { - let backoff = Backoff::new(); - loop { - let next = self.next.load(Ordering::Acquire); - if !next.is_null() { - return next; - } - backoff.snooze(); - } - } - - /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. - unsafe fn destroy(this: *mut Block, start: usize) { - // It is not necessary to set the `DESTROY` bit in the last slot because that slot has - // begun destruction of the block. - for i in start..BLOCK_CAP - 1 { - let slot = (*this).slots.get_unchecked(i); - - // Mark the `DESTROY` bit if a thread is still using the slot. - if slot.state.load(Ordering::Acquire) & READ == 0 - && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 - { - // If a thread is still using the slot, it will continue destruction of the block. - return; - } - } - - // No thread is using the block, now it is safe to destroy it. - drop(Box::from_raw(this)); - } -} - -/// A position in a queue. -struct Position { - /// The index in the queue. - index: AtomicUsize, - - /// The block in the linked list. - block: AtomicPtr>, -} - -/// An unbounded multi-producer multi-consumer queue. -/// -/// This queue is implemented as a linked list of segments, where each segment is a small buffer -/// that can hold a handful of elements. There is no limit to how many elements can be in the queue -/// at a time. However, since segments need to be dynamically allocated as elements get pushed, -/// this queue is somewhat slower than [`ArrayQueue`]. -/// -/// [`ArrayQueue`]: super::ArrayQueue -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::SegQueue; -/// -/// let q = SegQueue::new(); -/// -/// q.push('a'); -/// q.push('b'); -/// -/// assert_eq!(q.pop(), Some('a')); -/// assert_eq!(q.pop(), Some('b')); -/// assert!(q.pop().is_none()); -/// ``` -pub struct SegQueue { - /// The head of the queue. - head: CachePadded>, - - /// The tail of the queue. - tail: CachePadded>, - - /// Indicates that dropping a `SegQueue` may drop values of type `T`. - _marker: PhantomData, -} - -unsafe impl Send for SegQueue {} -unsafe impl Sync for SegQueue {} - -impl UnwindSafe for SegQueue {} -impl RefUnwindSafe for SegQueue {} - -impl SegQueue { - /// Creates a new unbounded queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::::new(); - /// ``` - pub const fn new() -> SegQueue { - SegQueue { - head: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - tail: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - _marker: PhantomData, - } - } - - /// Pushes an element into the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// q.push(20); - /// ``` - pub fn push(&self, value: T) { - let backoff = Backoff::new(); - let mut tail = self.tail.index.load(Ordering::Acquire); - let mut block = self.tail.block.load(Ordering::Acquire); - let mut next_block = None; - - loop { - // Calculate the offset of the index into the block. - let offset = (tail >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - - // If we're going to have to install the next block, allocate it in advance in order to - // make the wait for other threads as short as possible. - if offset + 1 == BLOCK_CAP && next_block.is_none() { - next_block = Some(Box::new(Block::::new())); - } - - // If this is the first push operation, we need to allocate the first block. - if block.is_null() { - let new = Box::into_raw(Box::new(Block::::new())); - - if self - .tail - .block - .compare_exchange(block, new, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - self.head.block.store(new, Ordering::Release); - block = new; - } else { - next_block = unsafe { Some(Box::from_raw(new)) }; - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - } - - let new_tail = tail + (1 << SHIFT); - - // Try advancing the tail forward. - match self.tail.index.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, install the next one. - if offset + 1 == BLOCK_CAP { - let next_block = Box::into_raw(next_block.unwrap()); - let next_index = new_tail.wrapping_add(1 << SHIFT); - - self.tail.block.store(next_block, Ordering::Release); - self.tail.index.store(next_index, Ordering::Release); - (*block).next.store(next_block, Ordering::Release); - } - - // Write the value into the slot. - let slot = (*block).slots.get_unchecked(offset); - slot.value.get().write(MaybeUninit::new(value)); - slot.state.fetch_or(WRITE, Ordering::Release); - - return; - }, - Err(t) => { - tail = t; - block = self.tail.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Pops an element from the queue. - /// - /// If the queue is empty, `None` is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// assert_eq!(q.pop(), Some(10)); - /// assert!(q.pop().is_none()); - /// ``` - pub fn pop(&self) -> Option { - let backoff = Backoff::new(); - let mut head = self.head.index.load(Ordering::Acquire); - let mut block = self.head.block.load(Ordering::Acquire); - - loop { - // Calculate the offset of the index into the block. - let offset = (head >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - continue; - } - - let mut new_head = head + (1 << SHIFT); - - if new_head & HAS_NEXT == 0 { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::Relaxed); - - // If the tail equals the head, that means the queue is empty. - if head >> SHIFT == tail >> SHIFT { - return None; - } - - // If head and tail are not in the same block, set `HAS_NEXT` in head. - if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { - new_head |= HAS_NEXT; - } - } - - // The block can be null here only if the first push operation is in progress. In that - // case, just wait until it gets initialized. - if block.is_null() { - backoff.snooze(); - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - continue; - } - - // Try moving the head index forward. - match self.head.index.compare_exchange_weak( - head, - new_head, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, move to the next one. - if offset + 1 == BLOCK_CAP { - let next = (*block).wait_next(); - let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); - if !(*next).next.load(Ordering::Relaxed).is_null() { - next_index |= HAS_NEXT; - } - - self.head.block.store(next, Ordering::Release); - self.head.index.store(next_index, Ordering::Release); - } - - // Read the value. - let slot = (*block).slots.get_unchecked(offset); - slot.wait_write(); - let value = slot.value.get().read().assume_init(); - - // Destroy the block if we've reached the end, or if another thread wanted to - // destroy but couldn't because we were busy reading from the slot. - if offset + 1 == BLOCK_CAP { - Block::destroy(block, 0); - } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { - Block::destroy(block, offset + 1); - } - - return Some(value); - }, - Err(h) => { - head = h; - block = self.head.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// assert!(q.is_empty()); - /// q.push(1); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.index.load(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::SeqCst); - head >> SHIFT == tail >> SHIFT - } - - /// Returns the number of elements in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// assert_eq!(q.len(), 0); - /// - /// q.push(10); - /// assert_eq!(q.len(), 1); - /// - /// q.push(20); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail index, then load the head index. - let mut tail = self.tail.index.load(Ordering::SeqCst); - let mut head = self.head.index.load(Ordering::SeqCst); - - // If the tail index didn't change, we've got consistent indices to work with. - if self.tail.index.load(Ordering::SeqCst) == tail { - // Erase the lower bits. - tail &= !((1 << SHIFT) - 1); - head &= !((1 << SHIFT) - 1); - - // Fix up indices if they fall onto block ends. - if (tail >> SHIFT) & (LAP - 1) == LAP - 1 { - tail = tail.wrapping_add(1 << SHIFT); - } - if (head >> SHIFT) & (LAP - 1) == LAP - 1 { - head = head.wrapping_add(1 << SHIFT); - } - - // Rotate indices so that head falls into the first block. - let lap = (head >> SHIFT) / LAP; - tail = tail.wrapping_sub((lap * LAP) << SHIFT); - head = head.wrapping_sub((lap * LAP) << SHIFT); - - // Remove the lower bits. - tail >>= SHIFT; - head >>= SHIFT; - - // Return the difference minus the number of blocks between tail and head. - return tail - head - tail / LAP; - } - } - } -} - -impl Drop for SegQueue { - fn drop(&mut self) { - let mut head = *self.head.index.get_mut(); - let mut tail = *self.tail.index.get_mut(); - let mut block = *self.head.block.get_mut(); - - // Erase the lower bits. - head &= !((1 << SHIFT) - 1); - tail &= !((1 << SHIFT) - 1); - - unsafe { - // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks. - while head != tail { - let offset = (head >> SHIFT) % LAP; - - if offset < BLOCK_CAP { - // Drop the value in the slot. - let slot = (*block).slots.get_unchecked(offset); - (*slot.value.get()).assume_init_drop(); - } else { - // Deallocate the block and move to the next one. - let next = *(*block).next.get_mut(); - drop(Box::from_raw(block)); - block = next; - } - - head = head.wrapping_add(1 << SHIFT); - } - - // Deallocate the last remaining block. - if !block.is_null() { - drop(Box::from_raw(block)); - } - } - } -} - -impl fmt::Debug for SegQueue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("SegQueue { .. }") - } -} - -impl Default for SegQueue { - fn default() -> SegQueue { - SegQueue::new() - } -} - -impl IntoIterator for SegQueue { - type Item = T; - - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter { value: self } - } -} - -#[derive(Debug)] -pub struct IntoIter { - value: SegQueue, -} - -impl Iterator for IntoIter { - type Item = T; - - fn next(&mut self) -> Option { - let value = &mut self.value; - let head = *value.head.index.get_mut(); - let tail = *value.tail.index.get_mut(); - if head >> SHIFT == tail >> SHIFT { - None - } else { - let block = *value.head.block.get_mut(); - let offset = (head >> SHIFT) % LAP; - - // SAFETY: We have mutable access to this, so we can read without - // worrying about concurrency. Furthermore, we know this is - // initialized because it is the value pointed at by `value.head` - // and this is a non-empty queue. - let item = unsafe { - let slot = (*block).slots.get_unchecked(offset); - slot.value.get().read().assume_init() - }; - if offset + 1 == BLOCK_CAP { - // Deallocate the block and move to the next one. - // SAFETY: The block is initialized because we've been reading - // from it this entire time. We can drop it b/c everything has - // been read out of it, so nothing is pointing to it anymore. - unsafe { - let next = *(*block).next.get_mut(); - drop(Box::from_raw(block)); - *value.head.block.get_mut() = next; - } - // The last value in a block is empty, so skip it - *value.head.index.get_mut() = head.wrapping_add(2 << SHIFT); - // Double-check that we're pointing to the first item in a block. - debug_assert_eq!((*value.head.index.get_mut() >> SHIFT) % LAP, 0); - } else { - *value.head.index.get_mut() = head.wrapping_add(1 << SHIFT); - } - Some(item) - } - } -} diff --git a/third-party/vendor/crossbeam-queue/tests/array_queue.rs b/third-party/vendor/crossbeam-queue/tests/array_queue.rs deleted file mode 100644 index b9d4e5fd..00000000 --- a/third-party/vendor/crossbeam-queue/tests/array_queue.rs +++ /dev/null @@ -1,374 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; - -use crossbeam_queue::ArrayQueue; -use crossbeam_utils::thread::scope; -use rand::{thread_rng, Rng}; - -#[test] -fn smoke() { - let q = ArrayQueue::new(1); - - q.push(7).unwrap(); - assert_eq!(q.pop(), Some(7)); - - q.push(8).unwrap(); - assert_eq!(q.pop(), Some(8)); - assert!(q.pop().is_none()); -} - -#[test] -fn capacity() { - for i in 1..10 { - let q = ArrayQueue::::new(i); - assert_eq!(q.capacity(), i); - } -} - -#[test] -#[should_panic(expected = "capacity must be non-zero")] -fn zero_capacity() { - let _ = ArrayQueue::::new(0); -} - -#[test] -fn len_empty_full() { - let q = ArrayQueue::new(2); - - assert_eq!(q.len(), 0); - assert!(q.is_empty()); - assert!(!q.is_full()); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 1); - assert!(!q.is_empty()); - assert!(!q.is_full()); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 2); - assert!(!q.is_empty()); - assert!(q.is_full()); - - q.pop().unwrap(); - - assert_eq!(q.len(), 1); - assert!(!q.is_empty()); - assert!(!q.is_full()); -} - -#[test] -fn len() { - #[cfg(miri)] - const COUNT: usize = 30; - #[cfg(not(miri))] - const COUNT: usize = 25_000; - #[cfg(miri)] - const CAP: usize = 40; - #[cfg(not(miri))] - const CAP: usize = 1000; - const ITERS: usize = CAP / 20; - - let q = ArrayQueue::new(CAP); - assert_eq!(q.len(), 0); - - for _ in 0..CAP / 10 { - for i in 0..ITERS { - q.push(i).unwrap(); - assert_eq!(q.len(), i + 1); - } - - for i in 0..ITERS { - q.pop().unwrap(); - assert_eq!(q.len(), ITERS - i - 1); - } - } - assert_eq!(q.len(), 0); - - for i in 0..CAP { - q.push(i).unwrap(); - assert_eq!(q.len(), i + 1); - } - - for _ in 0..CAP { - q.pop().unwrap(); - } - assert_eq!(q.len(), 0); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Some(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - let len = q.len(); - assert!(len <= CAP); - } - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - let len = q.len(); - assert!(len <= CAP); - } - }); - }) - .unwrap(); - assert_eq!(q.len(), 0); -} - -#[test] -fn spsc() { - #[cfg(miri)] - const COUNT: usize = 50; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - - let q = ArrayQueue::new(3); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Some(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_none()); - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - }) - .unwrap(); -} - -#[test] -fn spsc_ring_buffer() { - #[cfg(miri)] - const COUNT: usize = 50; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - - let t = AtomicUsize::new(1); - let q = ArrayQueue::::new(3); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - scope.spawn(|_| loop { - match t.load(Ordering::SeqCst) { - 0 if q.is_empty() => break, - - _ => { - while let Some(n) = q.pop() { - v[n].fetch_add(1, Ordering::SeqCst); - } - } - } - }); - - scope.spawn(|_| { - for i in 0..COUNT { - if let Some(n) = q.force_push(i) { - v[n].fetch_add(1, Ordering::SeqCst); - } - } - - t.fetch_sub(1, Ordering::SeqCst); - }); - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), 1); - } -} - -#[test] -fn mpmc() { - #[cfg(miri)] - const COUNT: usize = 50; - #[cfg(not(miri))] - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::::new(3); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - let n = loop { - if let Some(x) = q.pop() { - break x; - } - }; - v[n].fetch_add(1, Ordering::SeqCst); - } - }); - } - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[test] -fn mpmc_ring_buffer() { - #[cfg(miri)] - const COUNT: usize = 50; - #[cfg(not(miri))] - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let t = AtomicUsize::new(THREADS); - let q = ArrayQueue::::new(3); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| loop { - match t.load(Ordering::SeqCst) { - 0 if q.is_empty() => break, - - _ => { - while let Some(n) = q.pop() { - v[n].fetch_add(1, Ordering::SeqCst); - } - } - } - }); - } - - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - if let Some(n) = q.force_push(i) { - v[n].fetch_add(1, Ordering::SeqCst); - } - } - - t.fetch_sub(1, Ordering::SeqCst); - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[test] -fn drops() { - let runs: usize = if cfg!(miri) { 3 } else { 100 }; - let steps: usize = if cfg!(miri) { 50 } else { 10_000 }; - let additional: usize = if cfg!(miri) { 10 } else { 50 }; - - static DROPS: AtomicUsize = AtomicUsize::new(0); - - #[derive(Debug, PartialEq)] - struct DropCounter; - - impl Drop for DropCounter { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - let mut rng = thread_rng(); - - for _ in 0..runs { - let steps = rng.gen_range(0..steps); - let additional = rng.gen_range(0..additional); - - DROPS.store(0, Ordering::SeqCst); - let q = ArrayQueue::new(50); - - scope(|scope| { - scope.spawn(|_| { - for _ in 0..steps { - while q.pop().is_none() {} - } - }); - - scope.spawn(|_| { - for _ in 0..steps { - while q.push(DropCounter).is_err() { - DROPS.fetch_sub(1, Ordering::SeqCst); - } - } - }); - }) - .unwrap(); - - for _ in 0..additional { - q.push(DropCounter).unwrap(); - } - - assert_eq!(DROPS.load(Ordering::SeqCst), steps); - drop(q); - assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); - } -} - -#[test] -fn linearizable() { - #[cfg(miri)] - const COUNT: usize = 100; - #[cfg(not(miri))] - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::new(THREADS); - - scope(|scope| { - for _ in 0..THREADS / 2 { - scope.spawn(|_| { - for _ in 0..COUNT { - while q.push(0).is_err() {} - q.pop().unwrap(); - } - }); - - scope.spawn(|_| { - for _ in 0..COUNT { - if q.force_push(0).is_none() { - q.pop().unwrap(); - } - } - }); - } - }) - .unwrap(); -} - -#[test] -fn into_iter() { - let q = ArrayQueue::new(100); - for i in 0..100 { - q.push(i).unwrap(); - } - for (i, j) in q.into_iter().enumerate() { - assert_eq!(i, j); - } -} diff --git a/third-party/vendor/crossbeam-queue/tests/seg_queue.rs b/third-party/vendor/crossbeam-queue/tests/seg_queue.rs deleted file mode 100644 index bf5fb998..00000000 --- a/third-party/vendor/crossbeam-queue/tests/seg_queue.rs +++ /dev/null @@ -1,195 +0,0 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; - -use crossbeam_queue::SegQueue; -use crossbeam_utils::thread::scope; -use rand::{thread_rng, Rng}; - -#[test] -fn smoke() { - let q = SegQueue::new(); - q.push(7); - assert_eq!(q.pop(), Some(7)); - - q.push(8); - assert_eq!(q.pop(), Some(8)); - assert!(q.pop().is_none()); -} - -#[test] -fn len_empty_full() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - assert!(q.is_empty()); - - q.push(()); - - assert_eq!(q.len(), 1); - assert!(!q.is_empty()); - - q.pop().unwrap(); - - assert_eq!(q.len(), 0); - assert!(q.is_empty()); -} - -#[test] -fn len() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - - for i in 0..50 { - q.push(i); - assert_eq!(q.len(), i + 1); - } - - for i in 0..50 { - q.pop().unwrap(); - assert_eq!(q.len(), 50 - i - 1); - } - - assert_eq!(q.len(), 0); -} - -#[test] -fn spsc() { - #[cfg(miri)] - const COUNT: usize = 100; - #[cfg(not(miri))] - const COUNT: usize = 100_000; - - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Some(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_none()); - }); - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - }) - .unwrap(); -} - -#[test] -fn mpmc() { - #[cfg(miri)] - const COUNT: usize = 50; - #[cfg(not(miri))] - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = SegQueue::::new(); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - let n = loop { - if let Some(x) = q.pop() { - break x; - } - }; - v[n].fetch_add(1, Ordering::SeqCst); - } - }); - } - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[test] -fn drops() { - let runs: usize = if cfg!(miri) { 5 } else { 100 }; - let steps: usize = if cfg!(miri) { 50 } else { 10_000 }; - let additional: usize = if cfg!(miri) { 100 } else { 1_000 }; - - static DROPS: AtomicUsize = AtomicUsize::new(0); - - #[derive(Debug, PartialEq)] - struct DropCounter; - - impl Drop for DropCounter { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - let mut rng = thread_rng(); - - for _ in 0..runs { - let steps = rng.gen_range(0..steps); - let additional = rng.gen_range(0..additional); - - DROPS.store(0, Ordering::SeqCst); - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for _ in 0..steps { - while q.pop().is_none() {} - } - }); - - scope.spawn(|_| { - for _ in 0..steps { - q.push(DropCounter); - } - }); - }) - .unwrap(); - - for _ in 0..additional { - q.push(DropCounter); - } - - assert_eq!(DROPS.load(Ordering::SeqCst), steps); - drop(q); - assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); - } -} - -#[test] -fn into_iter() { - let q = SegQueue::new(); - for i in 0..100 { - q.push(i); - } - for (i, j) in q.into_iter().enumerate() { - assert_eq!(i, j); - } -} - -#[test] -fn into_iter_drop() { - let q = SegQueue::new(); - for i in 0..100 { - q.push(i); - } - for (i, j) in q.into_iter().enumerate().take(50) { - assert_eq!(i, j); - } -} diff --git a/third-party/vendor/crossbeam/.cargo-checksum.json b/third-party/vendor/crossbeam/.cargo-checksum.json deleted file mode 100644 index 0b3cdf08..00000000 --- a/third-party/vendor/crossbeam/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"87ba1b0829aea990ab3d7f2a30899c9d5e1067fba07c2abefae1fd004f2a5982","Cargo.toml":"9411d90fcc5e6badf13c9b3c133f2330b2b900dc4c851cfea36b8035cad7ca40","LICENSE-APACHE":"6f712474a3e3be1386d2d0c29449850ea788da64d35cff0fc8799acf741e9ecd","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","README.md":"dbe15407a26bdae7ecdcb376b8c62170104156f12c3c1ed8b121e9d6e763d63b","build-common.rs":"502cb7494549bed6fa10ac7bea36e880eeb60290dc69b679ac5c92b376469562","no_atomic.rs":"31a8276afd38e39987a169eeb02e9bed32670de5ca36d7eb74aab7e506cf9dc4","src/lib.rs":"27e0ffe5571c303464e8e30b6e2d486ccb342cb4293d49f282666e1f63fc39cc","tests/subcrates.rs":"bb9715e661d65bf9e61d41ad838f09dc531d624e705ab8650e1ee549a1e1feaf"},"package":"1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"} \ No newline at end of file diff --git a/third-party/vendor/crossbeam/CHANGELOG.md b/third-party/vendor/crossbeam/CHANGELOG.md deleted file mode 100644 index e881a9db..00000000 --- a/third-party/vendor/crossbeam/CHANGELOG.md +++ /dev/null @@ -1,105 +0,0 @@ -# Version 0.8.4 - -- Remove dependency on `cfg-if`. (#1072) - -# Version 0.8.3 - -- Bump the minimum supported Rust version to 1.61. (#1037) - -# Version 0.8.2 - -- Bump the minimum supported Rust version to 1.38. (#877) - -# Version 0.8.1 - -- Support targets that do not have atomic CAS on stable Rust (#698) - -# Version 0.8.0 - -- Bump the minimum supported Rust version to 1.36. -- Bump `crossbeam-channel` to `0.5`. -- Bump `crossbeam-deque` to `0.8`. -- Bump `crossbeam-epoch` to `0.9`. -- Bump `crossbeam-queue` to `0.3`. -- Bump `crossbeam-utils` to `0.8`. - -# Version 0.7.3 - -- Fix breakage with nightly feature due to rust-lang/rust#65214. -- Bump `crossbeam-channel` to `0.4`. -- Bump `crossbeam-epoch` to `0.8`. -- Bump `crossbeam-queue` to `0.2`. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.7.2 - -- Bump `crossbeam-channel` to `0.3.9`. -- Bump `crossbeam-epoch` to `0.7.2`. -- Bump `crossbeam-utils` to `0.6.6`. - -# Version 0.7.1 - -- Bump `crossbeam-utils` to `0.6.5`. - -# Version 0.7.0 - -- Remove `ArcCell`, `MsQueue`, and `TreiberStack`. -- Change the interface of `ShardedLock` to match `RwLock`. -- Add `SegQueue::len()`. -- Rename `SegQueue::try_pop()` to `SegQueue::pop()`. -- Change the return type of `SegQueue::pop()` to `Result`. -- Introduce `ArrayQueue`. -- Update dependencies. - -# Version 0.6.0 - -- Update dependencies. - -# Version 0.5.0 - -- Update `crossbeam-channel` to 0.3. -- Update `crossbeam-utils` to 0.6. -- Add `AtomicCell`, `SharedLock`, and `WaitGroup`. - -# Version 0.4.1 - -- Fix a double-free bug in `MsQueue` and `SegQueue`. - -# Version 0.4 - -- Switch to the new implementation of epoch-based reclamation in - [`crossbeam-epoch`](https://github.com/crossbeam-rs/crossbeam-epoch), fixing numerous bugs in the - old implementation. Its API is changed in a backward-incompatible way. -- Switch to the new implementation of `CachePadded` and scoped thread in - [`crossbeam-utils`](https://github.com/crossbeam-rs/crossbeam-utils). The scoped thread API is - changed in a backward-incompatible way. -- Switch to the new implementation of Chase-Lev deque in - [`crossbeam-deque`](https://github.com/crossbeam-rs/crossbeam-deque). Its API is changed in a - backward-incompatible way. -- Export channel implemented in - [`crossbeam-channel`](https://github.com/crossbeam-rs/crossbeam-channel). -- Remove `AtomicOption`. -- Implement `Default` and `From` traits. - -# Version 0.3 - -- Introduced `ScopedThreadBuilder` with the ability to name threads and set stack size -- `Worker` methods in the Chase-Lev deque don't require mutable access anymore -- Fixed a bug when unblocking `pop()` in `MsQueue` -- Implemented `Drop` for `MsQueue`, `SegQueue`, and `TreiberStack` -- Implemented `Default` for `TreiberStack` -- Added `is_empty` to `SegQueue` -- Renamed `mem::epoch` to `epoch` -- Other bug fixes - -# Version 0.2 - -- Changed existing non-blocking `pop` methods to `try_pop` -- Added blocking `pop` support to Michael-Scott queue -- Added Chase-Lev work-stealing deque - -# Version 0.1 - -- Added [epoch-based memory management](http://aturon.github.io/blog/2015/08/27/epoch/) -- Added Michael-Scott queue -- Added Segmented array queue diff --git a/third-party/vendor/crossbeam/Cargo.toml b/third-party/vendor/crossbeam/Cargo.toml deleted file mode 100644 index 768bbc3d..00000000 --- a/third-party/vendor/crossbeam/Cargo.toml +++ /dev/null @@ -1,86 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.61" -name = "crossbeam" -version = "0.8.4" -exclude = [ - "/.*", - "/ci", - "/tools", -] -description = "Tools for concurrent programming" -homepage = "https://github.com/crossbeam-rs/crossbeam" -readme = "README.md" -keywords = [ - "atomic", - "garbage", - "non-blocking", - "lock-free", - "rcu", -] -categories = [ - "concurrency", - "memory-management", - "data-structures", - "no-std", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/crossbeam-rs/crossbeam" - -[dependencies.crossbeam-channel] -version = "0.5.10" -optional = true -default-features = false - -[dependencies.crossbeam-deque] -version = "0.8.4" -optional = true -default-features = false - -[dependencies.crossbeam-epoch] -version = "0.9.17" -optional = true -default-features = false - -[dependencies.crossbeam-queue] -version = "0.3.10" -optional = true -default-features = false - -[dependencies.crossbeam-utils] -version = "0.8.18" -default-features = false - -[dev-dependencies.rand] -version = "0.8" - -[features] -alloc = [ - "crossbeam-epoch/alloc", - "crossbeam-queue/alloc", -] -default = ["std"] -nightly = [ - "crossbeam-epoch/nightly", - "crossbeam-utils/nightly", - "crossbeam-queue/nightly", -] -std = [ - "alloc", - "crossbeam-channel/std", - "crossbeam-deque/std", - "crossbeam-epoch/std", - "crossbeam-queue/std", - "crossbeam-utils/std", -] diff --git a/third-party/vendor/crossbeam/LICENSE-APACHE b/third-party/vendor/crossbeam/LICENSE-APACHE deleted file mode 100644 index bb9abdd7..00000000 --- a/third-party/vendor/crossbeam/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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 2019 The Crossbeam Project Developers - -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/third-party/vendor/crossbeam/LICENSE-MIT b/third-party/vendor/crossbeam/LICENSE-MIT deleted file mode 100644 index 068d491f..00000000 --- a/third-party/vendor/crossbeam/LICENSE-MIT +++ /dev/null @@ -1,27 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2019 The Crossbeam Project Developers - -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/third-party/vendor/crossbeam/README.md b/third-party/vendor/crossbeam/README.md deleted file mode 100644 index de4fcf63..00000000 --- a/third-party/vendor/crossbeam/README.md +++ /dev/null @@ -1,158 +0,0 @@ -# Crossbeam - -[![Build Status](https://github.com/crossbeam-rs/crossbeam/workflows/CI/badge.svg)]( -https://github.com/crossbeam-rs/crossbeam/actions) -[![License](https://img.shields.io/badge/license-MIT_OR_Apache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam#license) -[![Cargo](https://img.shields.io/crates/v/crossbeam.svg)]( -https://crates.io/crates/crossbeam) -[![Documentation](https://docs.rs/crossbeam/badge.svg)]( -https://docs.rs/crossbeam) -[![Rust 1.61+](https://img.shields.io/badge/rust-1.61+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.com/invite/JXYwgWZ) - -This crate provides a set of tools for concurrent programming: - -#### Atomics - -* [`AtomicCell`], a thread-safe mutable memory location.(no_std) -* [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering.(no_std) - -#### Data structures - -* [`deque`], work-stealing deques for building task schedulers. -* [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction.(alloc) -* [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand.(alloc) - -#### Memory management - -* [`epoch`], an epoch-based garbage collector.(alloc) - -#### Thread synchronization - -* [`channel`], multi-producer multi-consumer channels for message passing. -* [`Parker`], a thread parking primitive. -* [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. -* [`WaitGroup`], for synchronizing the beginning or end of some computation. - -#### Utilities - -* [`Backoff`], for exponential backoff in spin loops.(no_std) -* [`CachePadded`], for padding and aligning a value to the length of a cache line.(no_std) -* [`scope`], for spawning threads that borrow local variables from the stack. - -*Features marked with (no_std) can be used in `no_std` environments.*
-*Features marked with (alloc) can be used in `no_std` environments, but only if `alloc` -feature is enabled.* - -[`AtomicCell`]: https://docs.rs/crossbeam/*/crossbeam/atomic/struct.AtomicCell.html -[`AtomicConsume`]: https://docs.rs/crossbeam/*/crossbeam/atomic/trait.AtomicConsume.html -[`deque`]: https://docs.rs/crossbeam/*/crossbeam/deque/index.html -[`ArrayQueue`]: https://docs.rs/crossbeam/*/crossbeam/queue/struct.ArrayQueue.html -[`SegQueue`]: https://docs.rs/crossbeam/*/crossbeam/queue/struct.SegQueue.html -[`channel`]: https://docs.rs/crossbeam/*/crossbeam/channel/index.html -[`Parker`]: https://docs.rs/crossbeam/*/crossbeam/sync/struct.Parker.html -[`ShardedLock`]: https://docs.rs/crossbeam/*/crossbeam/sync/struct.ShardedLock.html -[`WaitGroup`]: https://docs.rs/crossbeam/*/crossbeam/sync/struct.WaitGroup.html -[`epoch`]: https://docs.rs/crossbeam/*/crossbeam/epoch/index.html -[`Backoff`]: https://docs.rs/crossbeam/*/crossbeam/utils/struct.Backoff.html -[`CachePadded`]: https://docs.rs/crossbeam/*/crossbeam/utils/struct.CachePadded.html -[`scope`]: https://docs.rs/crossbeam/*/crossbeam/fn.scope.html - -## Crates - -The main `crossbeam` crate just [re-exports](src/lib.rs) tools from -smaller subcrates: - -* [`crossbeam-channel`](crossbeam-channel) - provides multi-producer multi-consumer channels for message passing. -* [`crossbeam-deque`](crossbeam-deque) - provides work-stealing deques, which are primarily intended for building task schedulers. -* [`crossbeam-epoch`](crossbeam-epoch) - provides epoch-based garbage collection for building concurrent data structures. -* [`crossbeam-queue`](crossbeam-queue) - provides concurrent queues that can be shared among threads. -* [`crossbeam-utils`](crossbeam-utils) - provides atomics, synchronization primitives, scoped threads, and other utilities. - -There is one more experimental subcrate that is not yet included in `crossbeam`: - -* [`crossbeam-skiplist`](crossbeam-skiplist) - provides concurrent maps and sets based on lock-free skip lists. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam = "0.8" -``` - -## Compatibility - -Crossbeam supports stable Rust releases going back at least six months, -and every time the minimum supported Rust version is increased, a new minor -version is released. Currently, the minimum supported Rust version is 1.61. - -## Contributing - -Crossbeam welcomes contribution from everyone in the form of suggestions, bug reports, -pull requests, and feedback. 💛 - -If you need ideas for contribution, there are several ways to get started: - -* Found a bug or have a feature request? - [Submit an issue](https://github.com/crossbeam-rs/crossbeam/issues/new)! -* Issues and PRs labeled with - [feedback wanted](https://github.com/crossbeam-rs/crossbeam/issues?utf8=%E2%9C%93&q=is%3Aopen+sort%3Aupdated-desc+label%3A%22feedback+wanted%22+) - need feedback from users and contributors. -* Issues labeled with - [good first issue](https://github.com/crossbeam-rs/crossbeam/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) - are relatively easy starter issues. - -#### RFCs - -We also have the [RFCs](https://github.com/crossbeam-rs/rfcs) repository for more -high-level discussion, which is the place where we brainstorm ideas and propose -substantial changes to Crossbeam. - -You are welcome to participate in any open -[issues](https://github.com/crossbeam-rs/rfcs/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) -or -[pull requests](https://github.com/crossbeam-rs/rfcs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc). - -#### Learning resources - -If you'd like to learn more about concurrency and non-blocking data structures, there's a -list of learning resources in our [wiki](https://github.com/crossbeam-rs/rfcs/wiki), -which includes relevant blog posts, papers, videos, and other similar projects. - -Another good place to visit is [merged RFCs](https://github.com/crossbeam-rs/rfcs/tree/master/text). -They contain elaborate descriptions and rationale for features we've introduced to -Crossbeam, but keep in mind that some of the written information is now out of date. - -#### Conduct - -The Crossbeam project adheres to the -[Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). -This describes the minimum behavior expected from all contributors. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -Some Crossbeam subcrates have additional licensing notices. -Take a look at other readme files in this repository for more information. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. diff --git a/third-party/vendor/crossbeam/build-common.rs b/third-party/vendor/crossbeam/build-common.rs deleted file mode 100644 index e91bb4d4..00000000 --- a/third-party/vendor/crossbeam/build-common.rs +++ /dev/null @@ -1,13 +0,0 @@ -// The target triplets have the form of 'arch-vendor-system'. -// -// When building for Linux (e.g. the 'system' part is -// 'linux-something'), replace the vendor with 'unknown' -// so that mapping to rust standard targets happens correctly. -fn convert_custom_linux_target(target: String) -> String { - let mut parts: Vec<&str> = target.split('-').collect(); - let system = parts.get(2); - if system == Some(&"linux") { - parts[1] = "unknown"; - }; - parts.join("-") -} diff --git a/third-party/vendor/crossbeam/no_atomic.rs b/third-party/vendor/crossbeam/no_atomic.rs deleted file mode 100644 index b97f3970..00000000 --- a/third-party/vendor/crossbeam/no_atomic.rs +++ /dev/null @@ -1,12 +0,0 @@ -// This file is @generated by no_atomic.sh. -// It is not intended for manual editing. - -const NO_ATOMIC: &[&str] = &[ - "bpfeb-unknown-none", - "bpfel-unknown-none", - "mipsel-sony-psx", - "msp430-none-elf", - "riscv32i-unknown-none-elf", - "riscv32im-unknown-none-elf", - "riscv32imc-unknown-none-elf", -]; diff --git a/third-party/vendor/crossbeam/src/lib.rs b/third-party/vendor/crossbeam/src/lib.rs deleted file mode 100644 index 1230e5dc..00000000 --- a/third-party/vendor/crossbeam/src/lib.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! Tools for concurrent programming. -//! -//! ## Atomics -//! -//! * [`AtomicCell`], a thread-safe mutable memory location. -//! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering. -//! -//! ## Data structures -//! -//! * [`deque`], work-stealing deques for building task schedulers. -//! * [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -//! * [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. -//! -//! ## Memory management -//! -//! * [`epoch`], an epoch-based garbage collector. -//! -//! ## Thread synchronization -//! -//! * [`channel`], multi-producer multi-consumer channels for message passing. -//! * [`Parker`], a thread parking primitive. -//! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. -//! * [`WaitGroup`], for synchronizing the beginning or end of some computation. -//! -//! ## Utilities -//! -//! * [`Backoff`], for exponential backoff in spin loops. -//! * [`CachePadded`], for padding and aligning a value to the length of a cache line. -//! * [`scope`], for spawning threads that borrow local variables from the stack. -//! -//! [`AtomicCell`]: atomic::AtomicCell -//! [`AtomicConsume`]: atomic::AtomicConsume -//! [`ArrayQueue`]: queue::ArrayQueue -//! [`SegQueue`]: queue::SegQueue -//! [`Parker`]: sync::Parker -//! [`ShardedLock`]: sync::ShardedLock -//! [`WaitGroup`]: sync::WaitGroup -//! [`Backoff`]: utils::Backoff -//! [`CachePadded`]: utils::CachePadded - -#![doc(test( - no_crate_inject, - attr( - deny(warnings, rust_2018_idioms), - allow(dead_code, unused_assignments, unused_variables) - ) -))] -#![warn( - missing_docs, - missing_debug_implementations, - rust_2018_idioms, - unreachable_pub -)] -#![cfg_attr(not(feature = "std"), no_std)] - -pub use crossbeam_utils::atomic; - -pub mod utils { - //! Miscellaneous utilities. - //! - //! * [`Backoff`], for exponential backoff in spin loops. - //! * [`CachePadded`], for padding and aligning a value to the length of a cache line. - - pub use crossbeam_utils::Backoff; - pub use crossbeam_utils::CachePadded; -} - -#[cfg(feature = "alloc")] -#[doc(inline)] -pub use {crossbeam_epoch as epoch, crossbeam_queue as queue}; - -#[cfg(feature = "std")] -#[doc(inline)] -pub use { - crossbeam_channel as channel, crossbeam_channel::select, crossbeam_deque as deque, - crossbeam_utils::sync, -}; - -#[cfg(feature = "std")] -#[cfg(not(crossbeam_loom))] -pub use crossbeam_utils::thread::{self, scope}; diff --git a/third-party/vendor/crossbeam/tests/subcrates.rs b/third-party/vendor/crossbeam/tests/subcrates.rs deleted file mode 100644 index f7d2f5de..00000000 --- a/third-party/vendor/crossbeam/tests/subcrates.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! Makes sure subcrates are properly re-exported. - -use crossbeam::select; - -#[test] -fn channel() { - let (s, r) = crossbeam::channel::bounded(1); - - select! { - send(s, 0) -> res => res.unwrap(), - recv(r) -> res => assert!(res.is_ok()), - } -} - -#[test] -fn deque() { - let w = crossbeam::deque::Worker::new_fifo(); - w.push(1); - let _ = w.pop(); -} - -#[test] -#[cfg_attr(miri, ignore)] // Miri ICE: https://github.com/crossbeam-rs/crossbeam/pull/870#issuecomment-1189209073 -fn epoch() { - crossbeam::epoch::pin(); -} - -#[test] -fn queue() { - let a = crossbeam::queue::ArrayQueue::new(10); - let _ = a.push(1); - let _ = a.pop(); -} - -#[test] -fn utils() { - crossbeam::utils::CachePadded::new(7); - - crossbeam::scope(|scope| { - scope.spawn(|_| ()); - }) - .unwrap(); - - crossbeam::thread::scope(|scope| { - scope.spawn(|_| ()); - }) - .unwrap(); -} diff --git a/third-party/vendor/eyre/.cargo-checksum.json b/third-party/vendor/eyre/.cargo-checksum.json deleted file mode 100644 index 236a9a76..00000000 --- a/third-party/vendor/eyre/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"b980ff14aa7e728c69b6966f68ade64cd6259b89d6b61a099bfd0dd47960990b","Cargo.lock":"4e4e145371cef95fe347e7b14731fbf8f8aef366f45eb45f37760892a966e35b","Cargo.toml":"ad05a3833cfb3693e44c8341e23a85bd88d9578833193341b1b016cdbf99b8fd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"d6083c077bb087914386be267b52b98bca521f9af5b40b7fd82960d3ae2d2e3a","build.rs":"fbd0d04cc64884da6b65ad460084ad49e56f8a14fba24a256e161cb18b15441c","examples/custom_handler.rs":"33fa83c1ac4a6af8511796cc3b4818d4d4a50fa5eac5b9533a91acd695337169","examples/eyre-usage.rs":"3380d5176d433209eadeb355c2884fd0d46dc6a636b7402fab8fae17f79fa6c0","src/backtrace.rs":"02e509dd794ee2814b1342879414373935bcc33b433e45a58193297e52f95db7","src/chain.rs":"342161434eaa3db018541a24e01531135b471dfac44f7d25c84875c4dc5692d1","src/context.rs":"97f5c3fbe0679db8203ba5983817124df0d888d39e4fc8a55f33f568b4c536e0","src/error.rs":"b2395cb008713ec5112d332c81d0edc293a71bb992dc0d1a42db67ec5301dc10","src/error/pyo3_compat.rs":"6a3b48211b5496944aac8e058cbca85d37f379b3fc18b57c5e00ce56832d47bc","src/fmt.rs":"101f0fc55eba79900dafe04874f2b8f144d5da884b2087b77cda9fc1588d4d8c","src/kind.rs":"12aa656231f87f33367ac1db011dee70f87adff119305cf9d40faf3140234436","src/lib.rs":"32812e58622ad0d0fcc862163fda9c0f13497bc38df5cdd214f04d78a6d069e6","src/macros.rs":"22f30ae6fa6c130db4fa15913caf690cb33429e69cbf9f6371db586f1e0a5002","src/option.rs":"06271311605414d5f850efdf61a8c6976730f90cb03dc0712faa53f051a34509","src/ptr.rs":"81c21f61e9063db1eea3152ced7f01dd02d78ec64d09bf7f8ea0936e1d9772ad","src/wrapper.rs":"1d92365de5b679cc8bd328895724e6f7283e48ebf826bdbfac594813b2f96243","tests/common/mod.rs":"8094c30a551b8d4b04b474e5d4094bfd56f714fd51a8e2f4636eb823c5d08b1c","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"bd6d59b699a2901de2bda3c40c899af4ee82e4e98617516ea41c327b99af51e1","tests/test_autotrait.rs":"18b0c73026e9bbbc5272e8ed832ccb2522a606b64d50c80316495013f6acc808","tests/test_boxed.rs":"badf6e661aa3076ca644f6c0275991c8d26c5d3684bb2cb260ca2f58482594e8","tests/test_chain.rs":"8c7a75e38d241e9931a3530b30fab80ef87488daeecf87c84f72069d34650188","tests/test_context.rs":"816bdfa55f2fda0abde014817e46227a2da3effa0f697cfa5d2ca218650b946e","tests/test_context_access.rs":"dc490cfc031ac3907314a578c9bb9dfa51be95b041a62f771e39b79d66b763d3","tests/test_convert.rs":"300644b4ebf0cb94b542f6e306779199bc7fce7cc7bec956a1156767d847ae44","tests/test_downcast.rs":"4172648f5f48d489fe5b2e0e962dc2c35624eef5f907192db63f11493a396008","tests/test_fmt.rs":"a1ed4b79bea5f04006868d5145980ea6936d2eb4feee4b87e2c675d4f0b465ff","tests/test_location.rs":"79725e31e961df162b6e1f1194e7a0e5f45740bbeb7700293c2880360050ae28","tests/test_macros.rs":"bd1577f801a24abfb2870de9af9a9224a49025cbc8227a3b237bc73669592ba7","tests/test_no_install.rs":"9b4d695d9c699d5c39c7c4fd178b30fe472e96efbf2e8e4448ce72d6f2b3101b","tests/test_option.rs":"ae49e0b486f35bcd485765b1f6ebd0e02173b574b11c279c5597caf2f84f8c71","tests/test_pyo3.rs":"a1006f46d317e9e7a0c7c57f3502b9af594b62cb717269fee220f175d9ba5f17","tests/test_repr.rs":"a105eba1500a0bd7e36895bf03d43e2c9dbb6c573a0051c80f7ea7bdac103f78","tests/test_source.rs":"7d3cc674b802e46f84230db2e72b9a66b3bff39ae8d0246ab31607a8e6c01f27","tests/test_toolchain.rs":"96f9aacc8d9fe33d6e1d90a8f329d54d7ad5880348c64a87894ca916321c8c10"},"package":"7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"} \ No newline at end of file diff --git a/third-party/vendor/eyre/CHANGELOG.md b/third-party/vendor/eyre/CHANGELOG.md deleted file mode 100644 index 1654c473..00000000 --- a/third-party/vendor/eyre/CHANGELOG.md +++ /dev/null @@ -1,91 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - - - -## [Unreleased] - ReleaseDate - -## [0.6.12] - 2024-01-31 -### Fixed -- Unsound cast to invalid type during Report downcast [by ten3roberts](https://github.com/eyre-rs/eyre/pull/143) - -## [0.6.11] - 2023-12-13 -### Fixed -- stale references to `Error` in docstrings [by birkenfeld](https://github.com/eyre-rs/eyre/pull/87) - -### Added -- one-argument ensure!($expr) [by sharnoff](https://github.com/eyre-rs/eyre/pull/86) -- documentation on the performance characteristics of `wrap_err` vs `wrap_err_with` [by akshayknarayan](https://github.com/eyre-rs/eyre/pull/93) - - tl;dr: `wrap_err_with` is faster unless the constructed error object already exists -- ~~automated conversion to external errors for ensure! and bail! [by j-baker](https://github.com/eyre-rs/eyre/pull/95)~~ breaking change: shelved for next major release -- eyre::Ok for generating eyre::Ok() without fully specifying the type [by kylewlacy](https://github.com/eyre-rs/eyre/pull/91) -- `OptionExt::ok_or_eyre` for yielding static `Report`s from `None` [by LeoniePhiline](https://github.com/eyre-rs/eyre/pull/125) - -### New Contributors -- @sharnoff made their first contribution in https://github.com/eyre-rs/eyre/pull/86 -- @akshayknarayan made their first contribution in https://github.com/eyre-rs/eyre/pull/93 -- @j-baker made their first contribution in https://github.com/eyre-rs/eyre/pull/95 -- @kylewlacy made their first contribution in https://github.com/eyre-rs/eyre/pull/91 -- @LeoniePhiline made their first contribution in https://github.com/eyre-rs/eyre/pull/129 - -~~## [0.6.10] - 2023-12-07~~ Yanked - -## [0.6.9] - 2023-11-17 -### Fixed -- stacked borrows when dropping [by TimDiekmann](https://github.com/eyre-rs/eyre/pull/81) -- miri validation errors through now stricter provenance [by ten3roberts](https://github.com/eyre-rs/eyre/pull/103) -- documentation on no_std support [by thenorili](https://github.com/eyre-rs/eyre/pull/111) - -### Added -- monorepo for eyre-related crates [by pksunkara](https://github.com/eyre-rs/eyre/pull/104), [[2]](https://github.com/eyre-rs/eyre/pull/105)[[3]](https://github.com/eyre-rs/eyre/pull/107) -- CONTRIBUTING.md [by yaahc](https://github.com/eyre-rs/eyre/pull/99) - -## [0.6.8] - 2022-04-04 -### Added -- `#[must_use]` to `Report` -- `must-install` feature to help reduce binary sizes when using a custom `EyreHandler` - -## [0.6.7] - 2022-02-24 -### Fixed -- missing track_caller annotation to new format arg capture constructor - -## [0.6.6] - 2022-01-19 -### Added -- support for format arguments capture on 1.58 and later - -## [0.6.5] - 2021-01-05 -### Added -- optional support for converting into `pyo3` exceptions - -## [0.6.4] - 2021-01-04 -### Fixed -- missing track_caller annotations to `wrap_err` related trait methods - -## [0.6.3] - 2020-11-10 -### Fixed -- missing track_caller annotation to autoref specialization functions - -## [0.6.2] - 2020-10-27 -### Fixed -- missing track_caller annotation to new_adhoc function - -## [0.6.1] - 2020-09-28 -### Added -- support for track_caller on rust versions where it is available - - - -[Unreleased]: https://github.com/eyre-rs/eyre/compare/v0.6.11...HEAD -[0.6.11]: https://github.com/eyre-rs/eyre/compare/v0.6.9...v0.6.11 -[0.6.9]: https://github.com/eyre-rs/eyre/compare/v0.6.8...v0.6.9 -[0.6.8]: https://github.com/eyre-rs/eyre/compare/v0.6.7...v0.6.8 -[0.6.7]: https://github.com/eyre-rs/eyre/compare/v0.6.6...v0.6.7 -[0.6.6]: https://github.com/eyre-rs/eyre/compare/v0.6.5...v0.6.6 -[0.6.5]: https://github.com/eyre-rs/eyre/compare/v0.6.4...v0.6.5 -[0.6.4]: https://github.com/eyre-rs/eyre/compare/v0.6.3...v0.6.4 -[0.6.3]: https://github.com/eyre-rs/eyre/compare/v0.6.2...v0.6.3 -[0.6.2]: https://github.com/eyre-rs/eyre/compare/v0.6.1...v0.6.2 -[0.6.1]: https://github.com/eyre-rs/eyre/releases/tag/v0.6.1 diff --git a/third-party/vendor/eyre/Cargo.lock b/third-party/vendor/eyre/Cargo.lock deleted file mode 100644 index 30e2874f..00000000 --- a/third-party/vendor/eyre/Cargo.lock +++ /dev/null @@ -1,504 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "basic-toml" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f2139706359229bfa8f19142ac1155b4b80beafb7a60471ac5dd109d4a19778" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "dissimilar" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" - -[[package]] -name = "eyre" -version = "0.6.12" -dependencies = [ - "anyhow", - "backtrace", - "futures", - "indenter", - "once_cell", - "pyo3", - "rustversion", - "syn", - "thiserror", - "trybuild", -] - -[[package]] -name = "futures" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" - -[[package]] -name = "futures-io" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" - -[[package]] -name = "futures-sink" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" - -[[package]] -name = "futures-task" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" - -[[package]] -name = "futures-util" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" -dependencies = [ - "futures-core", - "futures-sink", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "libc" -version = "0.2.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "proc-macro2" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pyo3" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8453b658fe480c3e70c8ed4e3d3ec33eb74988bd186561b0cc66b85c3bc4b" -dependencies = [ - "cfg-if", - "libc", - "memoffset", - "parking_lot", - "pyo3-build-config", - "pyo3-ffi", -] - -[[package]] -name = "pyo3-build-config" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5" -dependencies = [ - "once_cell", - "target-lexicon", -] - -[[package]] -name = "pyo3-ffi" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214929900fd25e6604661ed9cf349727c8920d47deff196c4e28165a6ef2a96b" -dependencies = [ - "libc", - "pyo3-build-config", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "serde" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "syn" -version = "2.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "target-lexicon" -version = "0.12.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" - -[[package]] -name = "termcolor" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "trybuild" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" -dependencies = [ - "basic-toml", - "dissimilar", - "glob", - "once_cell", - "serde", - "serde_derive", - "serde_json", - "termcolor", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third-party/vendor/eyre/Cargo.toml b/third-party/vendor/eyre/Cargo.toml deleted file mode 100644 index cfddd7d4..00000000 --- a/third-party/vendor/eyre/Cargo.toml +++ /dev/null @@ -1,84 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -rust-version = "1.65.0" -name = "eyre" -version = "0.6.12" -authors = [ - "David Tolnay ", - "Jane Lusby ", -] -description = "Flexible concrete Error Reporting type built on std::error::Error with customizable Reports" -documentation = "https://docs.rs/eyre" -readme = "README.md" -categories = ["rust-patterns"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/eyre-rs/eyre" - -[package.metadata.docs.rs] -rustdoc-args = [ - "--cfg", - "doc_cfg", -] -targets = ["x86_64-unknown-linux-gnu"] - -[package.metadata.workspaces] -independent = true - -[dependencies.indenter] -version = "0.3.0" - -[dependencies.once_cell] -version = "1.18.0" - -[dependencies.pyo3] -version = "0.20" -optional = true -default-features = false - -[dev-dependencies.anyhow] -version = "1.0.28" - -[dev-dependencies.backtrace] -version = "0.3.46" - -[dev-dependencies.futures] -version = "0.3" -default-features = false - -[dev-dependencies.pyo3] -version = "0.20" -features = ["auto-initialize"] -default-features = false - -[dev-dependencies.rustversion] -version = "1.0" - -[dev-dependencies.syn] -version = "2.0" -features = ["full"] - -[dev-dependencies.thiserror] -version = "1.0" - -[dev-dependencies.trybuild] -version = "1.0.19" -features = ["diff"] - -[features] -auto-install = [] -default = [ - "auto-install", - "track-caller", -] -track-caller = [] diff --git a/third-party/vendor/eyre/LICENSE-APACHE b/third-party/vendor/eyre/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/third-party/vendor/eyre/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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/third-party/vendor/eyre/LICENSE-MIT b/third-party/vendor/eyre/LICENSE-MIT deleted file mode 100644 index 31aa7938..00000000 --- a/third-party/vendor/eyre/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -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/third-party/vendor/eyre/README.md b/third-party/vendor/eyre/README.md deleted file mode 100644 index 56e80be1..00000000 --- a/third-party/vendor/eyre/README.md +++ /dev/null @@ -1,269 +0,0 @@ -eyre -==== - -[![Build Status][actions-badge]][actions-url] -[![Latest Version](https://img.shields.io/crates/v/eyre.svg)](https://crates.io/crates/eyre) -[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/eyre) -[![Discord chat][discord-badge]][discord-url] - -[actions-badge]: https://github.com/eyre-rs/eyre/workflows/Continuous%20integration/badge.svg -[actions-url]: https://github.com/eyre-rs/eyre/actions?query=workflow%3A%22Continuous+integration%22 -[discord-badge]: https://img.shields.io/discord/960645145018110012?label=eyre%20community%20discord -[discord-url]: https://discord.gg/z94RqmUTKB - -This library provides [`eyre::Report`][Report], a trait object based -error handling type for easy idiomatic error handling and reporting in Rust -applications. - -This crate is a fork of [`anyhow`] with support for customized -error reports. For more details on customization checkout the docs on -[`eyre::EyreHandler`]. - -## Custom Report Handlers - -The heart of this crate is its ability to swap out the Handler type to change -what information is carried alongside errors and how the end report is -formatted. This crate is meant to be used alongside companion crates that -customize its behavior. Below is a list of known crates that export report -handlers for eyre and short summaries of what features they provide. - -- [`stable-eyre`]: Switches the backtrace type from `std`'s to `backtrace-rs`'s - so that it can be captured on stable. The report format is identical to - `DefaultHandler`'s report format. -- [`color-eyre`]: Captures a `backtrace::Backtrace` and a - `tracing_error::SpanTrace`. Provides a `Help` trait for attaching warnings - and suggestions to error reports. The end report is then pretty printed with - the help of [`color-backtrace`], [`color-spantrace`], and `ansi_term`. Check - out the README on [`color-eyre`] for details on the report format. -- [`simple-eyre`]: A minimal `EyreHandler` that captures no additional - information, for when you do not wish to capture `Backtrace`s with errors. -- [`jane-eyre`]: A report handler crate that exists purely for the pun of it. - Currently just re-exports `color-eyre`. - -## Usage Recommendations and Stability Considerations - -**We recommend users do not re-export types from this library as part their own -public API for libraries with external users.** The main reason for this is -that it will make your library API break if we ever bump the major version -number on eyre and your users upgrade the eyre version they use in their -application code before you upgrade your own eyre dep version[^1]. - -However, even beyond this API stability hazard, there are other good reasons to -avoid using `eyre::Report` as your public error type. - -- You export an undocumented error interface that is otherwise still accessible - via downcast, making it hard for users to react to specific errors while not - preventing them from depending on details you didn't mean to make part of - your public API. - - This in turn makes the error types of all libraries you use a part of your - public API as well, and makes changing any of those libraries into an - undetectable runtime breakage. -- If many of your errors are constructed from strings you encourage your users - to use string comparision for reacting to specific errors which is brittle - and turns updating error messages into a potentially undetectable runtime - breakage. - -## Details - -- Use `Result`, or equivalently `eyre::Result`, as the - return type of any fallible function. - - Within the function, use `?` to easily propagate any error that implements the - `std::error::Error` trait. - - ```rust - use eyre::Result; - - fn get_cluster_info() -> Result { - let config = std::fs::read_to_string("cluster.json")?; - let map: ClusterMap = serde_json::from_str(&config)?; - Ok(map) - } - ``` - -- Wrap a lower level error with a new error created from a message to help the - person troubleshooting understand the chain of failures that occurred. A - low-level error like "No such file or directory" can be annoying to debug - without more information about what higher level step the application was in - the middle of. - - ```rust - use eyre::{WrapErr, Result}; - - fn main() -> Result<()> { - ... - it.detach().wrap_err("Failed to detach the important thing")?; - - let content = std::fs::read(path) - .wrap_err_with(|| format!("Failed to read instrs from {}", path))?; - ... - } - ``` - - ```console - Error: Failed to read instrs from ./path/to/instrs.json - - Caused by: - No such file or directory (os error 2) - ``` - -- Downcasting is supported and can be by value, by shared reference, or by - mutable reference as needed. - - ```rust - // If the error was caused by redaction, then return a - // tombstone instead of the content. - match root_cause.downcast_ref::() { - Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), - None => Err(error), - } - ``` - -- If using the nightly channel, a backtrace is captured and printed with the - error if the underlying error type does not already provide its own. In order - to see backtraces, they must be enabled through the environment variables - described in [`std::backtrace`]: - - - If you want panics and errors to both have backtraces, set - `RUST_BACKTRACE=1`; - - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; - - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and - `RUST_LIB_BACKTRACE=0`. - - The tracking issue for this feature is [rust-lang/rust#53487]. - - [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables - [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487 - -- Eyre works with any error type that has an impl of `std::error::Error`, - including ones defined in your crate. We do not bundle a `derive(Error)` macro - but you can write the impls yourself or use a standalone macro like - [thiserror]. - - ```rust - use thiserror::Error; - - #[derive(Error, Debug)] - pub enum FormatError { - #[error("Invalid header (expected {expected:?}, got {found:?})")] - InvalidHeader { - expected: String, - found: String, - }, - #[error("Missing attribute: {0}")] - MissingAttribute(String), - } - ``` - -- One-off error messages can be constructed using the `eyre!` macro, which - supports string interpolation and produces an `eyre::Report`. - - ```rust - return Err(eyre!("Missing attribute: {}", missing)); - ``` - -- On newer versions of the compiler (e.g. 1.58 and later) this macro also - supports format args captures. - - ```rust - return Err(eyre!("Missing attribute: {missing}")); - ``` - -## No-std support - -No-std support was removed in 2020 in [commit 608a16a] due to unaddressed upstream breakages. -[commit 608a16a]: -https://github.com/eyre-rs/eyre/pull/29/commits/608a16aa2c2c27eca6c88001cc94c6973c18f1d5 - -## Comparison to failure - -The `eyre::Report` type works something like `failure::Error`, but unlike -failure ours is built around the standard library's `std::error::Error` trait -rather than a separate trait `failure::Fail`. The standard library has adopted -the necessary improvements for this to be possible as part of [RFC 2504]. - -[RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md - -## Comparison to thiserror - -Use `eyre` if you don't think you'll do anything with an error other than -report it. This is common in application code. Use `thiserror` if you think -you need an error type that can be handled via match or reported. This is -common in library crates where you don't know how your users will handle -your errors. - -[thiserror]: https://github.com/dtolnay/thiserror - -## Compatibility with `anyhow` - -This crate does its best to be usable as a drop in replacement of `anyhow` and -vice-versa by `re-exporting` all of the renamed APIs with the names used in -`anyhow`, though there are some differences still. - -#### `Context` and `Option` - -As part of renaming `Context` to `WrapErr` we also intentionally do not -implement `WrapErr` for `Option`. This decision was made because `wrap_err` -implies that you're creating a new error that saves the old error as its -`source`. With `Option` there is no source error to wrap, so `wrap_err` ends up -being somewhat meaningless. - -Instead `eyre` offers [`OptionExt::ok_or_eyre`] to yield _static_ errors from `None`, -and intends for users to use the combinator functions provided by -`std`, converting `Option`s to `Result`s, for _dynamic_ errors. -So where you would write this with -anyhow: - -[`OptionExt::ok_or_eyre`]: https://docs.rs/eyre/latest/eyre/trait.OptionExt.html#tymethod.ok_or_eyre - -```rust -use anyhow::Context; - -let opt: Option<()> = None; -let result_static = opt.context("static error message"); -let result_dynamic = opt.with_context(|| format!("{} error message", "dynamic")); -``` - -With `eyre` we want users to write: - -```rust -use eyre::{eyre, OptionExt, Result}; - -let opt: Option<()> = None; -let result_static: Result<()> = opt.ok_or_eyre("static error message"); -let result_dynamic: Result<()> = opt.ok_or_else(|| eyre!("{} error message", "dynamic")); -``` - -**NOTE**: However, to help with porting we do provide a `ContextCompat` trait which -implements `context` for options which you can import to make existing -`.context` calls compile. - -[Report]: https://docs.rs/eyre/*/eyre/struct.Report.html -[`eyre::EyreHandler`]: https://docs.rs/eyre/*/eyre/trait.EyreHandler.html -[`eyre::WrapErr`]: https://docs.rs/eyre/*/eyre/trait.WrapErr.html -[`anyhow::Context`]: https://docs.rs/anyhow/*/anyhow/trait.Context.html -[`anyhow`]: https://github.com/dtolnay/anyhow -[`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html -[`stable-eyre`]: https://github.com/eyre-rs/stable-eyre -[`color-eyre`]: https://github.com/eyre-rs/color-eyre -[`jane-eyre`]: https://github.com/yaahc/jane-eyre -[`simple-eyre`]: https://github.com/eyre-rs/simple-eyre -[`color-spantrace`]: https://github.com/eyre-rs/color-spantrace -[`color-backtrace`]: https://github.com/athre0z/color-backtrace - -[^1]: example and explanation of breakage https://github.com/eyre-rs/eyre/issues/30#issuecomment-647650361 - -#### License - - -Licensed under either of
Apache License, Version -2.0 or MIT license at your option. - - -
- - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in this crate by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. - diff --git a/third-party/vendor/eyre/build.rs b/third-party/vendor/eyre/build.rs deleted file mode 100644 index e0b2d292..00000000 --- a/third-party/vendor/eyre/build.rs +++ /dev/null @@ -1,132 +0,0 @@ -use std::env; -use std::ffi::OsString; -use std::fs; -use std::path::Path; -use std::process::{Command, ExitStatus}; -use std::str; - -// This code exercises the surface area that we expect of the std Backtrace -// type. If the current toolchain is able to compile it, we go ahead and use -// backtrace in eyre. -const BACKTRACE_PROBE: &str = r#" - #![feature(backtrace)] - #![allow(dead_code)] - - use std::backtrace::{Backtrace, BacktraceStatus}; - use std::error::Error; - use std::fmt::{self, Display}; - - #[derive(Debug)] - struct E; - - impl Display for E { - fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { - unimplemented!() - } - } - - impl Error for E { - fn backtrace(&self) -> Option<&Backtrace> { - let backtrace = Backtrace::capture(); - match backtrace.status() { - BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {} - } - unimplemented!() - } - } -"#; - -const TRACK_CALLER_PROBE: &str = r#" - #![allow(dead_code)] - - #[track_caller] - fn foo() { - let _location = std::panic::Location::caller(); - } -"#; - -fn main() { - match compile_probe(BACKTRACE_PROBE) { - Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"), - _ => {} - } - - match compile_probe(TRACK_CALLER_PROBE) { - Some(status) if status.success() => println!("cargo:rustc-cfg=track_caller"), - _ => {} - } - - let version = match rustc_version_info() { - Some(version) => version, - None => return, - }; - - version.toolchain.set_feature(); - - if version.minor < 52 { - println!("cargo:rustc-cfg=eyre_no_fmt_arguments_as_str"); - } - - if version.minor < 58 { - println!("cargo:rustc-cfg=eyre_no_fmt_args_capture"); - } -} - -fn compile_probe(probe: &str) -> Option { - let rustc = env::var_os("RUSTC")?; - let out_dir = env::var_os("OUT_DIR")?; - let probefile = Path::new(&out_dir).join("probe.rs"); - fs::write(&probefile, probe).ok()?; - Command::new(rustc) - .arg("--edition=2018") - .arg("--crate-name=eyre_build") - .arg("--crate-type=lib") - .arg("--emit=metadata") - .arg("--out-dir") - .arg(out_dir) - .arg(probefile) - .status() - .ok() -} - -// TODO factor this toolchain parsing and related tests into its own file -#[derive(PartialEq)] -enum Toolchain { - Stable, - Beta, - Nightly, -} -impl Toolchain { - fn set_feature(self) { - match self { - Toolchain::Nightly => println!("cargo:rustc-cfg=nightly"), - Toolchain::Beta => println!("cargo:rustc-cfg=beta"), - Toolchain::Stable => println!("cargo:rustc-cfg=stable"), - } - } -} - -struct VersionInfo { - minor: u32, - toolchain: Toolchain, -} - -fn rustc_version_info() -> Option { - let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); - let output = Command::new(rustc).arg("--version").output().ok()?; - let version = str::from_utf8(&output.stdout).ok()?; - let mut pieces = version.split(['.', ' ', '-']); - if pieces.next() != Some("rustc") { - return None; - } - let _major: u32 = pieces.next()?.parse().ok()?; - let minor = pieces.next()?.parse().ok()?; - let _patch: u32 = pieces.next()?.parse().ok()?; - let toolchain = match pieces.next() { - Some("beta") => Toolchain::Beta, - Some("nightly") => Toolchain::Nightly, - _ => Toolchain::Stable, - }; - let version = VersionInfo { minor, toolchain }; - Some(version) -} diff --git a/third-party/vendor/eyre/examples/custom_handler.rs b/third-party/vendor/eyre/examples/custom_handler.rs deleted file mode 100644 index a6f0ab20..00000000 --- a/third-party/vendor/eyre/examples/custom_handler.rs +++ /dev/null @@ -1,81 +0,0 @@ -use backtrace::Backtrace; -use eyre::EyreHandler; -use std::error::Error; -use std::{fmt, iter}; - -fn main() -> eyre::Result<()> { - // Install our custom eyre report hook for constructing our custom Handlers - install().unwrap(); - - // construct a report with, hopefully, our custom handler! - let mut report = eyre::eyre!("hello from custom error town!"); - - // manually set the custom msg for this report after it has been constructed - if let Some(handler) = report.handler_mut().downcast_mut::() { - handler.custom_msg = Some("you're the best users, you know that right???"); - } - - // print that shit!! - Err(report) -} - -// define a handler that captures backtraces unless told not to -fn install() -> Result<(), impl Error> { - let capture_backtrace = std::env::var("RUST_BACKWARDS_TRACE") - .map(|val| val != "0") - .unwrap_or(true); - - let hook = Hook { capture_backtrace }; - - eyre::set_hook(Box::new(move |e| Box::new(hook.make_handler(e)))) -} - -struct Hook { - capture_backtrace: bool, -} - -impl Hook { - fn make_handler(&self, _error: &(dyn Error + 'static)) -> Handler { - let backtrace = if self.capture_backtrace { - Some(Backtrace::new()) - } else { - None - }; - - Handler { - backtrace, - custom_msg: None, - } - } -} - -struct Handler { - // custom configured backtrace capture - backtrace: Option, - // customizable message payload associated with reports - custom_msg: Option<&'static str>, -} - -impl EyreHandler for Handler { - fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.alternate() { - return fmt::Debug::fmt(error, f); - } - - let errors = iter::successors(Some(error), |error| (*error).source()); - - for (ind, error) in errors.enumerate() { - write!(f, "\n{:>4}: {}", ind, error)?; - } - - if let Some(backtrace) = self.backtrace.as_ref() { - writeln!(f, "\n\nBacktrace:\n{:?}", backtrace)?; - } - - if let Some(msg) = self.custom_msg.as_ref() { - writeln!(f, "\n\n{}", msg)?; - } - - Ok(()) - } -} diff --git a/third-party/vendor/eyre/examples/eyre-usage.rs b/third-party/vendor/eyre/examples/eyre-usage.rs deleted file mode 100644 index 77e7811d..00000000 --- a/third-party/vendor/eyre/examples/eyre-usage.rs +++ /dev/null @@ -1,7 +0,0 @@ -use eyre::{eyre, Report, WrapErr}; - -fn main() -> Result<(), Report> { - let e: Report = eyre!("oh no this program is just bad!"); - - Err(e).wrap_err("usage example successfully experienced a failure") -} diff --git a/third-party/vendor/eyre/src/backtrace.rs b/third-party/vendor/eyre/src/backtrace.rs deleted file mode 100644 index 6c00d7fa..00000000 --- a/third-party/vendor/eyre/src/backtrace.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[cfg(backtrace)] -pub(crate) use std::backtrace::Backtrace; - -#[cfg(not(backtrace))] -pub(crate) enum Backtrace {} - -#[cfg(backtrace)] -macro_rules! backtrace_if_absent { - ($err:expr) => { - match $err.backtrace() { - Some(_) => None, - None => Some(Backtrace::capture()), - } - }; -} - -#[cfg(not(backtrace))] -macro_rules! backtrace_if_absent { - ($err:expr) => { - None - }; -} diff --git a/third-party/vendor/eyre/src/chain.rs b/third-party/vendor/eyre/src/chain.rs deleted file mode 100644 index 78131f2e..00000000 --- a/third-party/vendor/eyre/src/chain.rs +++ /dev/null @@ -1,109 +0,0 @@ -use self::ChainState::*; -use crate::StdError; - -use std::vec; - -pub(crate) use crate::Chain; - -#[derive(Clone)] -pub(crate) enum ChainState<'a> { - Linked { - next: Option<&'a (dyn StdError + 'static)>, - }, - Buffered { - rest: vec::IntoIter<&'a (dyn StdError + 'static)>, - }, -} - -impl<'a> Chain<'a> { - /// Construct an iterator over a chain of errors via the `source` method - /// - /// # Example - /// - /// ```rust - /// use std::error::Error; - /// use std::fmt::{self, Write}; - /// use eyre::Chain; - /// use indenter::indented; - /// - /// fn report(error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// let mut errors = Chain::new(error).enumerate(); - /// for (i, error) in errors { - /// writeln!(f)?; - /// write!(indented(f).ind(i), "{}", error)?; - /// } - /// - /// Ok(()) - /// } - /// ``` - pub fn new(head: &'a (dyn StdError + 'static)) -> Self { - Chain { - state: ChainState::Linked { next: Some(head) }, - } - } -} - -impl<'a> Iterator for Chain<'a> { - type Item = &'a (dyn StdError + 'static); - - fn next(&mut self) -> Option { - match &mut self.state { - Linked { next } => { - let error = (*next)?; - *next = error.source(); - Some(error) - } - Buffered { rest } => rest.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} - -impl DoubleEndedIterator for Chain<'_> { - fn next_back(&mut self) -> Option { - match &mut self.state { - Linked { mut next } => { - let mut rest = Vec::new(); - while let Some(cause) = next { - next = cause.source(); - rest.push(cause); - } - let mut rest = rest.into_iter(); - let last = rest.next_back(); - self.state = Buffered { rest }; - last - } - Buffered { rest } => rest.next_back(), - } - } -} - -impl ExactSizeIterator for Chain<'_> { - fn len(&self) -> usize { - match &self.state { - Linked { mut next } => { - let mut len = 0; - while let Some(cause) = next { - next = cause.source(); - len += 1; - } - len - } - Buffered { rest } => rest.len(), - } - } -} - -impl Default for Chain<'_> { - fn default() -> Self { - Chain { - state: ChainState::Buffered { - rest: Vec::new().into_iter(), - }, - } - } -} diff --git a/third-party/vendor/eyre/src/context.rs b/third-party/vendor/eyre/src/context.rs deleted file mode 100644 index a15b41ba..00000000 --- a/third-party/vendor/eyre/src/context.rs +++ /dev/null @@ -1,192 +0,0 @@ -use crate::error::{ContextError, ErrorImpl}; -use crate::{ContextCompat, Report, StdError, WrapErr}; -use core::fmt::{self, Debug, Display, Write}; - -#[cfg(backtrace)] -use std::backtrace::Backtrace; - -mod ext { - use super::*; - - pub trait StdError { - #[cfg_attr(track_caller, track_caller)] - fn ext_report(self, msg: D) -> Report - where - D: Display + Send + Sync + 'static; - } - - impl StdError for E - where - E: std::error::Error + Send + Sync + 'static, - { - fn ext_report(self, msg: D) -> Report - where - D: Display + Send + Sync + 'static, - { - Report::from_msg(msg, self) - } - } - - impl StdError for Report { - fn ext_report(self, msg: D) -> Report - where - D: Display + Send + Sync + 'static, - { - self.wrap_err(msg) - } - } -} - -impl WrapErr for Result -where - E: ext::StdError + Send + Sync + 'static, -{ - fn wrap_err(self, msg: D) -> Result - where - D: Display + Send + Sync + 'static, - { - match self { - Ok(t) => Ok(t), - Err(e) => Err(e.ext_report(msg)), - } - } - - fn wrap_err_with(self, msg: F) -> Result - where - D: Display + Send + Sync + 'static, - F: FnOnce() -> D, - { - match self { - Ok(t) => Ok(t), - Err(e) => Err(e.ext_report(msg())), - } - } - - fn context(self, msg: D) -> Result - where - D: Display + Send + Sync + 'static, - { - self.wrap_err(msg) - } - - fn with_context(self, msg: F) -> Result - where - D: Display + Send + Sync + 'static, - F: FnOnce() -> D, - { - self.wrap_err_with(msg) - } -} - -impl ContextCompat for Option { - fn wrap_err(self, msg: D) -> Result - where - D: Display + Send + Sync + 'static, - { - self.context(msg) - } - - fn wrap_err_with(self, msg: F) -> Result - where - D: Display + Send + Sync + 'static, - F: FnOnce() -> D, - { - self.with_context(msg) - } - - fn context(self, msg: D) -> Result - where - D: Display + Send + Sync + 'static, - { - match self { - Some(t) => Ok(t), - None => Err(Report::from_display(msg)), - } - } - - fn with_context(self, msg: F) -> Result - where - D: Display + Send + Sync + 'static, - F: FnOnce() -> D, - { - match self { - Some(t) => Ok(t), - None => Err(Report::from_display(msg())), - } - } -} - -impl Debug for ContextError -where - D: Display, - E: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Error") - .field("msg", &Quoted(&self.msg)) - .field("source", &self.error) - .finish() - } -} - -impl Display for ContextError -where - D: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.msg, f) - } -} - -impl StdError for ContextError -where - D: Display, - E: StdError + 'static, -{ - #[cfg(backtrace)] - fn backtrace(&self) -> Option<&Backtrace> { - self.error.backtrace() - } - - fn source(&self) -> Option<&(dyn StdError + 'static)> { - Some(&self.error) - } -} - -impl StdError for ContextError -where - D: Display, -{ - fn source(&self) -> Option<&(dyn StdError + 'static)> { - Some(ErrorImpl::error(self.error.inner.as_ref())) - } -} - -struct Quoted(D); - -impl Debug for Quoted -where - D: Display, -{ - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_char('"')?; - Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?; - formatter.write_char('"')?; - Ok(()) - } -} - -impl Write for Quoted<&mut fmt::Formatter<'_>> { - fn write_str(&mut self, s: &str) -> fmt::Result { - Display::fmt(&s.escape_debug(), self.0) - } -} - -pub(crate) mod private { - use super::*; - - pub trait Sealed {} - - impl Sealed for Result where E: ext::StdError {} - impl Sealed for Option {} -} diff --git a/third-party/vendor/eyre/src/error.rs b/third-party/vendor/eyre/src/error.rs deleted file mode 100644 index 5a3d2d8b..00000000 --- a/third-party/vendor/eyre/src/error.rs +++ /dev/null @@ -1,912 +0,0 @@ -use crate::chain::Chain; -use crate::ptr::{MutPtr, OwnedPtr, RefPtr}; -use crate::EyreHandler; -use crate::{Report, StdError}; -use core::any::TypeId; -use core::fmt::{self, Debug, Display}; -use core::mem::{self, ManuallyDrop}; -use core::ptr::{self, NonNull}; - -use core::ops::{Deref, DerefMut}; - -impl Report { - /// Create a new error object from any error type. - /// - /// The error type must be threadsafe and `'static`, so that the `Report` - /// will be as well. - /// - /// If the error type does not provide a backtrace, a backtrace will be - /// created here to ensure that a backtrace exists. - #[cfg_attr(track_caller, track_caller)] - pub fn new(error: E) -> Self - where - E: StdError + Send + Sync + 'static, - { - Report::from_std(error) - } - - /// Create a new error object from a printable error message. - /// - /// If the argument implements std::error::Error, prefer `Report::new` - /// instead which preserves the underlying error's cause chain and - /// backtrace. If the argument may or may not implement std::error::Error - /// now or in the future, use `eyre!(err)` which handles either way - /// correctly. - /// - /// `Report::msg("...")` is equivalent to `eyre!("...")` but occasionally - /// convenient in places where a function is preferable over a macro, such - /// as iterator or stream combinators: - /// - /// ``` - /// # mod ffi { - /// # pub struct Input; - /// # pub struct Output; - /// # pub async fn do_some_work(_: Input) -> Result { - /// # unimplemented!() - /// # } - /// # } - /// # - /// # use ffi::{Input, Output}; - /// # - /// use eyre::{Report, Result}; - /// use futures::stream::{Stream, StreamExt, TryStreamExt}; - /// - /// async fn demo(stream: S) -> Result> - /// where - /// S: Stream, - /// { - /// stream - /// .then(ffi::do_some_work) // returns Result - /// .map_err(Report::msg) - /// .try_collect() - /// .await - /// } - /// ``` - #[cfg_attr(track_caller, track_caller)] - pub fn msg(message: M) -> Self - where - M: Display + Debug + Send + Sync + 'static, - { - Report::from_adhoc(message) - } - - #[cfg_attr(track_caller, track_caller)] - /// Creates a new error from an implementor of [`std::error::Error`] - pub(crate) fn from_std(error: E) -> Self - where - E: StdError + Send + Sync + 'static, - { - let vtable = &ErrorVTable { - object_drop: object_drop::, - object_ref: object_ref::, - object_mut: object_mut::, - object_boxed: object_boxed::, - object_downcast: object_downcast::, - object_downcast_mut: object_downcast_mut::, - object_drop_rest: object_drop_front::, - }; - - // Safety: passing vtable that operates on the right type E. - let handler = Some(crate::capture_handler(&error)); - - unsafe { Report::construct(error, vtable, handler) } - } - - #[cfg_attr(track_caller, track_caller)] - pub(crate) fn from_adhoc(message: M) -> Self - where - M: Display + Debug + Send + Sync + 'static, - { - use crate::wrapper::MessageError; - let error: MessageError = MessageError(message); - let vtable = &ErrorVTable { - object_drop: object_drop::>, - object_ref: object_ref::>, - object_mut: object_mut::>, - object_boxed: object_boxed::>, - object_downcast: object_downcast::, - object_downcast_mut: object_downcast_mut::, - object_drop_rest: object_drop_front::, - }; - - // Safety: MessageError is repr(transparent) so it is okay for the - // vtable to allow casting the MessageError to M. - let handler = Some(crate::capture_handler(&error)); - - unsafe { Report::construct(error, vtable, handler) } - } - - #[cfg_attr(track_caller, track_caller)] - pub(crate) fn from_display(message: M) -> Self - where - M: Display + Send + Sync + 'static, - { - use crate::wrapper::{DisplayError, NoneError}; - let error: DisplayError = DisplayError(message); - let vtable = &ErrorVTable { - object_drop: object_drop::>, - object_ref: object_ref::>, - object_mut: object_mut::>, - object_boxed: object_boxed::>, - object_downcast: object_downcast::, - object_downcast_mut: object_downcast_mut::, - object_drop_rest: object_drop_front::, - }; - - // Safety: DisplayError is repr(transparent) so it is okay for the - // vtable to allow casting the DisplayError to M. - let handler = Some(crate::capture_handler(&NoneError)); - - unsafe { Report::construct(error, vtable, handler) } - } - - #[cfg_attr(track_caller, track_caller)] - pub(crate) fn from_msg(msg: D, error: E) -> Self - where - D: Display + Send + Sync + 'static, - E: StdError + Send + Sync + 'static, - { - let error: ContextError = ContextError { msg, error }; - - let vtable = &ErrorVTable { - object_drop: object_drop::>, - object_ref: object_ref::>, - object_mut: object_mut::>, - object_boxed: object_boxed::>, - object_downcast: context_downcast::, - object_downcast_mut: context_downcast_mut::, - object_drop_rest: context_drop_rest::, - }; - - // Safety: passing vtable that operates on the right type. - let handler = Some(crate::capture_handler(&error)); - - unsafe { Report::construct(error, vtable, handler) } - } - - #[cfg_attr(track_caller, track_caller)] - pub(crate) fn from_boxed(error: Box) -> Self { - use crate::wrapper::BoxedError; - let error = BoxedError(error); - let handler = Some(crate::capture_handler(&error)); - - let vtable = &ErrorVTable { - object_drop: object_drop::, - object_ref: object_ref::, - object_mut: object_mut::, - object_boxed: object_boxed::, - object_downcast: object_downcast::>, - object_downcast_mut: object_downcast_mut::>, - object_drop_rest: object_drop_front::>, - }; - - // Safety: BoxedError is repr(transparent) so it is okay for the vtable - // to allow casting to Box. - unsafe { Report::construct(error, vtable, handler) } - } - - // Takes backtrace as argument rather than capturing it here so that the - // user sees one fewer layer of wrapping noise in the backtrace. - // - // Unsafe because the given vtable must have sensible behavior on the error - // value of type E. - unsafe fn construct( - error: E, - vtable: &'static ErrorVTable, - handler: Option>, - ) -> Self - where - E: StdError + Send + Sync + 'static, - { - let inner = ErrorImpl { - header: ErrorHeader { vtable, handler }, - _object: error, - }; - - // Construct a new owned allocation through a raw pointer - // - // This does not keep the allocation around as a `Box` which would invalidate an - // references when moved - let ptr = OwnedPtr::>::new(inner); - - // Safety: the type - let ptr = ptr.cast::>(); - Report { inner: ptr } - } - - /// Create a new error from an error message to wrap the existing error. - /// - /// For attaching a higher level error message to a `Result` as it is propagated, the - /// [`WrapErr`][crate::WrapErr] extension trait may be more convenient than this function. - /// - /// The primary reason to use `error.wrap_err(...)` instead of `result.wrap_err(...)` via the - /// `WrapErr` trait would be if the message needs to depend on some data held by the underlying - /// error: - /// - /// ``` - /// # use std::fmt::{self, Debug, Display}; - /// # - /// # type T = (); - /// # - /// # impl std::error::Error for ParseError {} - /// # impl Debug for ParseError { - /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - /// # unimplemented!() - /// # } - /// # } - /// # impl Display for ParseError { - /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - /// # unimplemented!() - /// # } - /// # } - /// # - /// use eyre::Result; - /// use std::fs::File; - /// use std::path::Path; - /// - /// struct ParseError { - /// line: usize, - /// column: usize, - /// } - /// - /// fn parse_impl(file: File) -> Result { - /// # const IGNORE: &str = stringify! { - /// ... - /// # }; - /// # unimplemented!() - /// } - /// - /// pub fn parse(path: impl AsRef) -> Result { - /// let file = File::open(&path)?; - /// parse_impl(file).map_err(|error| { - /// let message = format!( - /// "only the first {} lines of {} are valid", - /// error.line, path.as_ref().display(), - /// ); - /// eyre::Report::new(error).wrap_err(message) - /// }) - /// } - /// ``` - pub fn wrap_err(mut self, msg: D) -> Self - where - D: Display + Send + Sync + 'static, - { - // Safety: this access a `ErrorImpl` as a valid reference to a `ErrorImpl<()>` - // - // As the generic is at the end of the struct and the struct is `repr(C)` this reference - // will be within bounds of the original pointer, and the field will have the same offset - let handler = header_mut(self.inner.as_mut()).handler.take(); - let error: ContextError = ContextError { msg, error: self }; - - let vtable = &ErrorVTable { - object_drop: object_drop::>, - object_ref: object_ref::>, - object_mut: object_mut::>, - object_boxed: object_boxed::>, - object_downcast: context_chain_downcast::, - object_downcast_mut: context_chain_downcast_mut::, - object_drop_rest: context_chain_drop_rest::, - }; - - // Safety: passing vtable that operates on the right type. - unsafe { Report::construct(error, vtable, handler) } - } - - /// Access the vtable for the current error object. - fn vtable(&self) -> &'static ErrorVTable { - header(self.inner.as_ref()).vtable - } - - /// An iterator of the chain of source errors contained by this Report. - /// - /// This iterator will visit every error in the cause chain of this error - /// object, beginning with the error that this error object was created - /// from. - /// - /// # Example - /// - /// ``` - /// use eyre::Report; - /// use std::io; - /// - /// pub fn underlying_io_error_kind(error: &Report) -> Option { - /// for cause in error.chain() { - /// if let Some(io_error) = cause.downcast_ref::() { - /// return Some(io_error.kind()); - /// } - /// } - /// None - /// } - /// ``` - pub fn chain(&self) -> Chain<'_> { - ErrorImpl::chain(self.inner.as_ref()) - } - - /// The lowest level cause of this error — this error's cause's - /// cause's cause etc. - /// - /// The root cause is the last error in the iterator produced by - /// [`chain()`][Report::chain]. - pub fn root_cause(&self) -> &(dyn StdError + 'static) { - let mut chain = self.chain(); - let mut root_cause = chain.next().unwrap(); - for cause in chain { - root_cause = cause; - } - root_cause - } - - /// Returns true if `E` is the type held by this error object. - /// - /// For errors constructed from messages, this method returns true if `E` matches the type of - /// the message `D` **or** the type of the error on which the message has been attached. For - /// details about the interaction between message and downcasting, [see here]. - /// - /// [see here]: trait.WrapErr.html#effect-on-downcasting - pub fn is(&self) -> bool - where - E: Display + Debug + Send + Sync + 'static, - { - self.downcast_ref::().is_some() - } - - /// Attempt to downcast the error object to a concrete type. - pub fn downcast(self) -> Result - where - E: Display + Debug + Send + Sync + 'static, - { - let target = TypeId::of::(); - unsafe { - // Use vtable to find NonNull<()> which points to a value of type E - // somewhere inside the data structure. - let addr = match (self.vtable().object_downcast)(self.inner.as_ref(), target) { - Some(addr) => addr, - None => return Err(self), - }; - - // Prepare to read E out of the data structure. We'll drop the rest - // of the data structure separately so that E is not dropped. - let outer = ManuallyDrop::new(self); - - // Read E from where the vtable found it. - let error = ptr::read(addr.cast::().as_ptr()); - - // Read Box> from self. Can't move it out because - // Report has a Drop impl which we want to not run. - let inner = ptr::read(&outer.inner); - - // Drop rest of the data structure outside of E. - (outer.vtable().object_drop_rest)(inner, target); - - Ok(error) - } - } - - /// Downcast this error object by reference. - /// - /// # Example - /// - /// ``` - /// # use eyre::{Report, eyre}; - /// # use std::fmt::{self, Display}; - /// # use std::task::Poll; - /// # - /// # #[derive(Debug)] - /// # enum DataStoreError { - /// # Censored(()), - /// # } - /// # - /// # impl Display for DataStoreError { - /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - /// # unimplemented!() - /// # } - /// # } - /// # - /// # impl std::error::Error for DataStoreError {} - /// # - /// # const REDACTED_CONTENT: () = (); - /// # - /// # #[cfg(not(feature = "auto-install"))] - /// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); - /// # - /// # let error: Report = eyre!("..."); - /// # let root_cause = &error; - /// # - /// # let ret = - /// // If the error was caused by redaction, then return a tombstone instead - /// // of the content. - /// match root_cause.downcast_ref::() { - /// Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), - /// None => Err(error), - /// } - /// # ; - /// ``` - pub fn downcast_ref(&self) -> Option<&E> - where - E: Display + Debug + Send + Sync + 'static, - { - let target = TypeId::of::(); - unsafe { - // Use vtable to find NonNull<()> which points to a value of type E - // somewhere inside the data structure. - let addr = (self.vtable().object_downcast)(self.inner.as_ref(), target)?; - Some(addr.cast::().as_ref()) - } - } - - /// Downcast this error object by mutable reference. - pub fn downcast_mut(&mut self) -> Option<&mut E> - where - E: Display + Debug + Send + Sync + 'static, - { - let target = TypeId::of::(); - unsafe { - // Use vtable to find NonNull<()> which points to a value of type E - // somewhere inside the data structure. - let addr = (self.vtable().object_downcast_mut)(self.inner.as_mut(), target)?; - Some(addr.cast::().as_mut()) - } - } - - /// Get a reference to the Handler for this Report. - pub fn handler(&self) -> &dyn EyreHandler { - header(self.inner.as_ref()) - .handler - .as_ref() - .unwrap() - .as_ref() - } - - /// Get a mutable reference to the Handler for this Report. - pub fn handler_mut(&mut self) -> &mut dyn EyreHandler { - header_mut(self.inner.as_mut()) - .handler - .as_mut() - .unwrap() - .as_mut() - } - - /// Get a reference to the Handler for this Report. - #[doc(hidden)] - pub fn context(&self) -> &dyn EyreHandler { - header(self.inner.as_ref()) - .handler - .as_ref() - .unwrap() - .as_ref() - } - - /// Get a mutable reference to the Handler for this Report. - #[doc(hidden)] - pub fn context_mut(&mut self) -> &mut dyn EyreHandler { - header_mut(self.inner.as_mut()) - .handler - .as_mut() - .unwrap() - .as_mut() - } -} - -impl From for Report -where - E: StdError + Send + Sync + 'static, -{ - #[cfg_attr(track_caller, track_caller)] - fn from(error: E) -> Self { - Report::from_std(error) - } -} - -impl Deref for Report { - type Target = dyn StdError + Send + Sync + 'static; - - fn deref(&self) -> &Self::Target { - ErrorImpl::error(self.inner.as_ref()) - } -} - -impl DerefMut for Report { - fn deref_mut(&mut self) -> &mut Self::Target { - ErrorImpl::error_mut(self.inner.as_mut()) - } -} - -impl Display for Report { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - ErrorImpl::display(self.inner.as_ref(), formatter) - } -} - -impl Debug for Report { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - ErrorImpl::debug(self.inner.as_ref(), formatter) - } -} - -impl Drop for Report { - fn drop(&mut self) { - unsafe { - // Read Box> from self. - (self.vtable().object_drop)(self.inner); - } - } -} - -struct ErrorVTable { - object_drop: unsafe fn(OwnedPtr>), - object_ref: unsafe fn(RefPtr<'_, ErrorImpl<()>>) -> &(dyn StdError + Send + Sync + 'static), - object_mut: unsafe fn(MutPtr<'_, ErrorImpl<()>>) -> &mut (dyn StdError + Send + Sync + 'static), - #[allow(clippy::type_complexity)] - object_boxed: unsafe fn(OwnedPtr>) -> Box, - object_downcast: unsafe fn(RefPtr<'_, ErrorImpl<()>>, TypeId) -> Option>, - object_downcast_mut: unsafe fn(MutPtr<'_, ErrorImpl<()>>, TypeId) -> Option>, - object_drop_rest: unsafe fn(OwnedPtr>, TypeId), -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl. -unsafe fn object_drop(e: OwnedPtr>) { - // Cast to a context type and drop the Box allocation. - let unerased = unsafe { e.cast::>().into_box() }; - drop(unerased); -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl. -unsafe fn object_drop_front(e: OwnedPtr>, target: TypeId) { - // Drop the fields of ErrorImpl other than E as well as the Box allocation, - // without dropping E itself. This is used by downcast after doing a - // ptr::read to take ownership of the E. - let _ = target; - // Note: This must not use `mem::transmute` because it tries to reborrow the `Unique` - // contained in `Box`, which must not be done. In practice this probably won't make any - // difference by now, but technically it's unsound. - // see: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.m - let unerased = unsafe { e.cast::>().into_box() }; - - mem::forget(unerased._object) -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl. -unsafe fn object_ref(e: RefPtr<'_, ErrorImpl<()>>) -> &(dyn StdError + Send + Sync + 'static) -where - E: StdError + Send + Sync + 'static, -{ - // Attach E's native StdError vtable onto a pointer to self._object. - &unsafe { e.cast::>().as_ref() }._object -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl. -unsafe fn object_mut(e: MutPtr<'_, ErrorImpl<()>>) -> &mut (dyn StdError + Send + Sync + 'static) -where - E: StdError + Send + Sync + 'static, -{ - // Attach E's native StdError vtable onto a pointer to self._object. - &mut unsafe { e.cast::>().into_mut() }._object -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl. -unsafe fn object_boxed(e: OwnedPtr>) -> Box -where - E: StdError + Send + Sync + 'static, -{ - // Attach ErrorImpl's native StdError vtable. The StdError impl is below. - unsafe { e.cast::>().into_box() } -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl. -unsafe fn object_downcast(e: RefPtr<'_, ErrorImpl<()>>, target: TypeId) -> Option> -where - E: 'static, -{ - if TypeId::of::() == target { - // Caller is looking for an E pointer and e is ErrorImpl, take a - // pointer to its E field. - let unerased = unsafe { e.cast::>().as_ref() }; - Some(NonNull::from(&(unerased._object)).cast::<()>()) - } else { - None - } -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl. -unsafe fn object_downcast_mut( - e: MutPtr<'_, ErrorImpl<()>>, - target: TypeId, -) -> Option> -where - E: 'static, -{ - if TypeId::of::() == target { - // Caller is looking for an E pointer and e is ErrorImpl, take a - // pointer to its E field. - let unerased = unsafe { e.cast::>().into_mut() }; - Some(NonNull::from(&mut (unerased._object)).cast::<()>()) - } else { - None - } -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl>. -unsafe fn context_downcast( - e: RefPtr<'_, ErrorImpl<()>>, - target: TypeId, -) -> Option> -where - D: 'static, - E: 'static, -{ - if TypeId::of::() == target { - let unerased = unsafe { e.cast::>>().as_ref() }; - let addr = NonNull::from(&unerased._object.msg).cast::<()>(); - Some(addr) - } else if TypeId::of::() == target { - let unerased = unsafe { e.cast::>>().as_ref() }; - let addr = NonNull::from(&unerased._object.error).cast::<()>(); - Some(addr) - } else { - None - } -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl>. -unsafe fn context_downcast_mut( - e: MutPtr<'_, ErrorImpl<()>>, - target: TypeId, -) -> Option> -where - D: 'static, - E: 'static, -{ - if TypeId::of::() == target { - let unerased = unsafe { e.cast::>>().into_mut() }; - let addr = NonNull::from(&unerased._object.msg).cast::<()>(); - Some(addr) - } else if TypeId::of::() == target { - let unerased = unsafe { e.cast::>>().into_mut() }; - let addr = NonNull::from(&mut unerased._object.error).cast::<()>(); - Some(addr) - } else { - None - } -} -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl>. -unsafe fn context_drop_rest(e: OwnedPtr>, target: TypeId) -where - D: 'static, - E: 'static, -{ - // Called after downcasting by value to either the D or the E and doing a - // ptr::read to take ownership of that value. - if TypeId::of::() == target { - unsafe { - e.cast::, E>>>() - .into_box() - }; - } else { - debug_assert_eq!(TypeId::of::(), target); - unsafe { - e.cast::>>>() - .into_box() - }; - } -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl>. -unsafe fn context_chain_downcast( - e: RefPtr<'_, ErrorImpl<()>>, - target: TypeId, -) -> Option> -where - D: 'static, -{ - let unerased = unsafe { e.cast::>>().as_ref() }; - if TypeId::of::() == target { - let addr = NonNull::from(&unerased._object.msg).cast::<()>(); - Some(addr) - } else { - // Recurse down the context chain per the inner error's vtable. - let source = &unerased._object.error; - unsafe { (source.vtable().object_downcast)(source.inner.as_ref(), target) } - } -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl>. -unsafe fn context_chain_downcast_mut( - e: MutPtr<'_, ErrorImpl<()>>, - target: TypeId, -) -> Option> -where - D: 'static, -{ - let unerased = unsafe { e.cast::>>().into_mut() }; - if TypeId::of::() == target { - let addr = NonNull::from(&unerased._object.msg).cast::<()>(); - Some(addr) - } else { - // Recurse down the context chain per the inner error's vtable. - let source = &mut unerased._object.error; - unsafe { (source.vtable().object_downcast_mut)(source.inner.as_mut(), target) } - } -} - -/// # Safety -/// -/// Requires layout of *e to match ErrorImpl>. -unsafe fn context_chain_drop_rest(e: OwnedPtr>, target: TypeId) -where - D: 'static, -{ - // Called after downcasting by value to either the D or one of the causes - // and doing a ptr::read to take ownership of that value. - if TypeId::of::() == target { - let unerased = unsafe { - e.cast::, Report>>>() - .into_box() - }; - // Drop the entire rest of the data structure rooted in the next Report. - drop(unerased); - } else { - unsafe { - let unerased = e - .cast::>>>() - .into_box(); - // Read out a ManuallyDrop>> from the next error. - let inner = ptr::read(&unerased.as_ref()._object.error.inner); - drop(unerased); - // Recursively drop the next error using the same target typeid. - (header(inner.as_ref()).vtable.object_drop_rest)(inner, target); - } - } -} - -#[repr(C)] -pub(crate) struct ErrorHeader { - vtable: &'static ErrorVTable, - pub(crate) handler: Option>, -} - -// repr C to ensure that E remains in the final position. -#[repr(C)] -pub(crate) struct ErrorImpl { - header: ErrorHeader, - // NOTE: Don't use directly. Use only through vtable. Erased type may have - // different alignment. - _object: E, -} - -// repr C to ensure that ContextError has the same layout as -// ContextError, E> and ContextError>. -#[repr(C)] -pub(crate) struct ContextError { - pub(crate) msg: D, - pub(crate) error: E, -} - -impl ErrorImpl { - /// Returns a type erased Error - fn erase(&self) -> RefPtr<'_, ErrorImpl<()>> { - // Erase the concrete type of E but preserve the vtable in self.vtable - // for manipulating the resulting thin pointer. This is analogous to an - // unsize coersion. - RefPtr::new(self).cast() - } -} - -// Reads the header out of `p`. This is the same as `p.as_ref().header`, but -// avoids converting `p` into a reference of a shrunk provenance with a type different than the -// allocation. -fn header(p: RefPtr<'_, ErrorImpl<()>>) -> &'_ ErrorHeader { - // Safety: `ErrorHeader` is the first field of repr(C) `ErrorImpl` - unsafe { p.cast().as_ref() } -} - -fn header_mut(p: MutPtr<'_, ErrorImpl<()>>) -> &mut ErrorHeader { - // Safety: `ErrorHeader` is the first field of repr(C) `ErrorImpl` - unsafe { p.cast().into_mut() } -} - -impl ErrorImpl<()> { - pub(crate) fn error(this: RefPtr<'_, Self>) -> &(dyn StdError + Send + Sync + 'static) { - // Use vtable to attach E's native StdError vtable for the right - // original type E. - unsafe { (header(this).vtable.object_ref)(this) } - } - - pub(crate) fn error_mut(this: MutPtr<'_, Self>) -> &mut (dyn StdError + Send + Sync + 'static) { - // Use vtable to attach E's native StdError vtable for the right - // original type E. - unsafe { (header_mut(this).vtable.object_mut)(this) } - } - - pub(crate) fn chain(this: RefPtr<'_, Self>) -> Chain<'_> { - Chain::new(Self::error(this)) - } - - pub(crate) fn header(this: RefPtr<'_, ErrorImpl>) -> &ErrorHeader { - header(this) - } -} - -impl StdError for ErrorImpl -where - E: StdError, -{ - fn source(&self) -> Option<&(dyn StdError + 'static)> { - ErrorImpl::<()>::error(self.erase()).source() - } -} - -impl Debug for ErrorImpl -where - E: Debug, -{ - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - ErrorImpl::debug(self.erase(), formatter) - } -} - -impl Display for ErrorImpl -where - E: Display, -{ - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(ErrorImpl::error(self.erase()), formatter) - } -} - -impl From for Box { - fn from(error: Report) -> Self { - let outer = ManuallyDrop::new(error); - unsafe { - // Read Box> from error. Can't move it out because - // Report has a Drop impl which we want to not run. - // Use vtable to attach ErrorImpl's native StdError vtable for - // the right original type E. - (header(outer.inner.as_ref()).vtable.object_boxed)(outer.inner) - } - } -} - -impl From for Box { - fn from(error: Report) -> Self { - Box::::from(error) - } -} - -impl AsRef for Report { - fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) { - &**self - } -} - -impl AsRef for Report { - fn as_ref(&self) -> &(dyn StdError + 'static) { - &**self - } -} - -#[cfg(feature = "pyo3")] -mod pyo3_compat; diff --git a/third-party/vendor/eyre/src/error/pyo3_compat.rs b/third-party/vendor/eyre/src/error/pyo3_compat.rs deleted file mode 100644 index b70b6a54..00000000 --- a/third-party/vendor/eyre/src/error/pyo3_compat.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::Report; - -impl From for pyo3::PyErr { - fn from(error: Report) -> Self { - pyo3::exceptions::PyRuntimeError::new_err(format!("{:?}", error)) - } -} diff --git a/third-party/vendor/eyre/src/fmt.rs b/third-party/vendor/eyre/src/fmt.rs deleted file mode 100644 index c66620e2..00000000 --- a/third-party/vendor/eyre/src/fmt.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::{error::ErrorImpl, ptr::RefPtr}; -use core::fmt; - -impl ErrorImpl<()> { - pub(crate) fn display(this: RefPtr<'_, Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ErrorImpl::header(this) - .handler - .as_ref() - .map(|handler| handler.display(Self::error(this), f)) - .unwrap_or_else(|| core::fmt::Display::fmt(Self::error(this), f)) - } - - /// Debug formats the error using the captured handler - pub(crate) fn debug(this: RefPtr<'_, Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - ErrorImpl::header(this) - .handler - .as_ref() - .map(|handler| handler.debug(Self::error(this), f)) - .unwrap_or_else(|| core::fmt::Debug::fmt(Self::error(this), f)) - } -} diff --git a/third-party/vendor/eyre/src/kind.rs b/third-party/vendor/eyre/src/kind.rs deleted file mode 100644 index bb7c5c0b..00000000 --- a/third-party/vendor/eyre/src/kind.rs +++ /dev/null @@ -1,111 +0,0 @@ -#![allow(missing_debug_implementations, missing_docs)] -// Tagged dispatch mechanism for resolving the behavior of `eyre!($expr)`. -// -// When eyre! is given a single expr argument to turn into eyre::Report, we -// want the resulting Report to pick up the input's implementation of source() -// and backtrace() if it has a std::error::Error impl, otherwise require nothing -// more than Display and Debug. -// -// Expressed in terms of specialization, we want something like: -// -// trait EyreNew { -// fn new(self) -> Report; -// } -// -// impl EyreNew for T -// where -// T: Display + Debug + Send + Sync + 'static, -// { -// default fn new(self) -> Report { -// /* no std error impl */ -// } -// } -// -// impl EyreNew for T -// where -// T: std::error::Error + Send + Sync + 'static, -// { -// fn new(self) -> Report { -// /* use std error's source() and backtrace() */ -// } -// } -// -// Since specialization is not stable yet, instead we rely on autoref behavior -// of method resolution to perform tagged dispatch. Here we have two traits -// AdhocKind and TraitKind that both have an eyre_kind() method. AdhocKind is -// implemented whether or not the caller's type has a std error impl, while -// TraitKind is implemented only when a std error impl does exist. The ambiguity -// is resolved by AdhocKind requiring an extra autoref so that it has lower -// precedence. -// -// The eyre! macro will set up the call in this form: -// -// #[allow(unused_imports)] -// use $crate::private::{AdhocKind, TraitKind}; -// let error = $msg; -// (&error).eyre_kind().new(error) - -use crate::Report; -use core::fmt::{Debug, Display}; - -use crate::StdError; - -pub struct Adhoc; - -pub trait AdhocKind: Sized { - #[inline] - fn eyre_kind(&self) -> Adhoc { - Adhoc - } -} - -impl AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {} - -impl Adhoc { - #[cfg_attr(track_caller, track_caller)] - pub fn new(self, message: M) -> Report - where - M: Display + Debug + Send + Sync + 'static, - { - Report::from_adhoc(message) - } -} - -pub struct Trait; - -pub trait TraitKind: Sized { - #[inline] - fn eyre_kind(&self) -> Trait { - Trait - } -} - -impl TraitKind for E where E: Into {} - -impl Trait { - #[cfg_attr(track_caller, track_caller)] - pub fn new(self, error: E) -> Report - where - E: Into, - { - error.into() - } -} - -pub struct Boxed; - -pub trait BoxedKind: Sized { - #[inline] - fn eyre_kind(&self) -> Boxed { - Boxed - } -} - -impl BoxedKind for Box {} - -impl Boxed { - #[cfg_attr(track_caller, track_caller)] - pub fn new(self, error: Box) -> Report { - Report::from_boxed(error) - } -} diff --git a/third-party/vendor/eyre/src/lib.rs b/third-party/vendor/eyre/src/lib.rs deleted file mode 100644 index 64ca5984..00000000 --- a/third-party/vendor/eyre/src/lib.rs +++ /dev/null @@ -1,1322 +0,0 @@ -//! This library provides [`eyre::Report`][Report], a trait object based -//! error handling type for easy idiomatic error handling and reporting in Rust -//! applications. -//! -//! This crate is a fork of [`anyhow`] with support for customized -//! error reports. For more details on customization, check out the docs on -//! [`eyre::EyreHandler`]. -//! -//! ## Custom Report Handlers -//! -//! The heart of this crate is its ability to swap out the Handler type to change -//! what information is carried alongside errors and how the end report is -//! formatted. This crate is meant to be used alongside companion crates that -//! customize its behavior. Below is a list of known crates that export report -//! handlers for eyre and short summaries of what features they provide. -//! -//! - [`stable-eyre`]: Switches the backtrace type from `std`'s to `backtrace-rs`'s -//! so that it can be captured on stable. The report format is identical to -//! `DefaultHandler`'s report format. -//! - [`color-eyre`]: Captures a `backtrace::Backtrace` and a -//! `tracing_error::SpanTrace`. Provides a `Section` trait for attaching warnings -//! and suggestions to error reports. The end report is then pretty printed with -//! the help of [`color-backtrace`], [`color-spantrace`], and `ansi_term`. Check -//! out the README on [`color-eyre`] for details on the report format. -//! - [`simple-eyre`]: A minimal `EyreHandler` that captures no additional -//! information, for when you do not wish to capture `Backtrace`s with errors. -//! - [`jane-eyre`]: A report handler crate that exists purely for the pun. -//! Currently just re-exports `color-eyre`. -//! -//! ## Usage Recommendations and Stability Considerations -//! -//! **We recommend users do not re-export types from this library as part their -//! own public API for libraries with external users.** The main reason for this -//! is that it will make your library API break if we ever bump the major version -//! number on eyre and your users upgrade the eyre version they use in their -//! application code before you upgrade your own eyre dep version[^1]. -//! -//! However, even beyond this API stability hazard, there are other good reasons -//! to avoid using `eyre::Report` as your public error type. -//! -//! - You export an undocumented error interface that is otherwise still -//! accessible via downcast, making it hard for users to react to specific -//! errors while not preventing them from depending on details you didn't mean -//! to make part of your public API. -//! - This in turn makes the error types of all libraries you use a part of -//! your public API as well, and makes changing any of those libraries into -//! undetectable runtime breakage. -//! - If many of your errors are constructed from strings, you encourage your -//! users to use string comparison for reacting to specific errors, which is -//! brittle and turns updating error messages into potentially undetectable -//! runtime breakage. -//! -//! ## Details -//! -//! - Use `Result`, or equivalently `eyre::Result`, as the -//! return type of any fallible function. -//! -//! Within the function, use `?` to easily propagate any error that implements the -//! `std::error::Error` trait. -//! -//! ```rust -//! # pub trait Deserialize {} -//! # -//! # mod serde_json { -//! # use super::Deserialize; -//! # use std::io; -//! # -//! # pub fn from_str(json: &str) -> io::Result { -//! # unimplemented!() -//! # } -//! # } -//! # -//! # struct ClusterMap; -//! # -//! # impl Deserialize for ClusterMap {} -//! # -//! use eyre::Result; -//! -//! fn get_cluster_info() -> Result { -//! let config = std::fs::read_to_string("cluster.json")?; -//! let map: ClusterMap = serde_json::from_str(&config)?; -//! Ok(map) -//! } -//! # -//! # fn main() {} -//! ``` -//! -//! - Wrap a lower level error with a new error created from a message to help the -//! person troubleshooting understand the chain of failures that occurred. A -//! low-level error like "No such file or directory" can be annoying to debug -//! without more information about what higher level step the application was in -//! the middle of. -//! -//! ```rust -//! # struct It; -//! # -//! # impl It { -//! # fn detach(&self) -> Result<()> { -//! # unimplemented!() -//! # } -//! # } -//! # -//! use eyre::{WrapErr, Result}; -//! -//! fn main() -> Result<()> { -//! # return Ok(()); -//! # -//! # const _: &str = stringify! { -//! ... -//! # }; -//! # -//! # let it = It; -//! # let path = "./path/to/instrs.json"; -//! # -//! it.detach().wrap_err("Failed to detach the important thing")?; -//! -//! let content = std::fs::read(path) -//! .wrap_err_with(|| format!("Failed to read instrs from {}", path))?; -//! # -//! # const _: &str = stringify! { -//! ... -//! # }; -//! # -//! # Ok(()) -//! } -//! ``` -//! -//! ```console -//! Error: Failed to read instrs from ./path/to/instrs.json -//! -//! Caused by: -//! No such file or directory (os error 2) -//! ``` -//! -//! - Downcasting is supported and can be done by value, by shared reference, or by -//! mutable reference as needed. -//! -//! ```rust -//! # use eyre::{Report, eyre}; -//! # use std::fmt::{self, Display}; -//! # use std::task::Poll; -//! # -//! # #[derive(Debug)] -//! # enum DataStoreError { -//! # Censored(()), -//! # } -//! # -//! # impl Display for DataStoreError { -//! # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { -//! # unimplemented!() -//! # } -//! # } -//! # -//! # impl std::error::Error for DataStoreError {} -//! # -//! # const REDACTED_CONTENT: () = (); -//! # -//! # #[cfg(not(feature = "auto-install"))] -//! # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); -//! # -//! # let error: Report = eyre!("..."); -//! # let root_cause = &error; -//! # -//! # let ret = -//! // If the error was caused by redaction, then return a -//! // tombstone instead of the content. -//! match root_cause.downcast_ref::() { -//! Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)), -//! None => Err(error), -//! } -//! # ; -//! ``` -//! -//! - If using the nightly channel, a backtrace is captured and printed with the -//! error if the underlying error type does not already provide its own. In order -//! to see backtraces, they must be enabled through the environment variables -//! described in [`std::backtrace`]: -//! -//! - If you want panics and errors to both have backtraces, set -//! `RUST_BACKTRACE=1`; -//! - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`; -//! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and -//! `RUST_LIB_BACKTRACE=0`. -//! -//! The tracking issue for this feature is [rust-lang/rust#53487]. -//! -//! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables -//! [rust-lang/rust#53487]: https://github.com/rust-lang/rust/issues/53487 -//! -//! - Eyre works with any error type that has an impl of `std::error::Error`, -//! including ones defined in your crate. We do not bundle a `derive(Error)` macro -//! but you can write the impls yourself or use a standalone macro like -//! [thiserror]. -//! -//! ```rust -//! use thiserror::Error; -//! -//! #[derive(Error, Debug)] -//! pub enum FormatError { -//! #[error("Invalid header (expected {expected:?}, got {found:?})")] -//! InvalidHeader { -//! expected: String, -//! found: String, -//! }, -//! #[error("Missing attribute: {0}")] -//! MissingAttribute(String), -//! } -//! ``` -//! -//! - One-off error messages can be constructed using the `eyre!` macro, which -//! supports string interpolation and produces an `eyre::Report`. -//! -//! ```rust -//! # use eyre::{eyre, Result}; -//! # -//! # fn demo() -> Result<()> { -//! # let missing = "..."; -//! return Err(eyre!("Missing attribute: {}", missing)); -//! # Ok(()) -//! # } -//! ``` -//! -//! - On newer versions of the compiler (i.e. 1.58 and later) this macro also -//! supports format args captures. -//! -//! ```rust -//! # use eyre::{eyre, Result}; -//! # -//! # fn demo() -> Result<()> { -//! # let missing = "..."; -//! # #[cfg(not(eyre_no_fmt_args_capture))] -//! return Err(eyre!("Missing attribute: {missing}")); -//! # Ok(()) -//! # } -//! ``` -//! -//! ## No-std support -//! -//! No-std support was removed in 2020 in [commit 608a16a] due to unaddressed upstream breakages. -//! -//! [commit 608a16a]: https://github.com/eyre-rs/eyre/pull/29/commits/608a16aa2c2c27eca6c88001cc94c6973c18f1d5 -//! -//! ## Comparison to failure -//! -//! The `eyre::Report` type works something like `failure::Error`, but unlike -//! failure ours is built around the standard library's `std::error::Error` trait -//! rather than a separate trait `failure::Fail`. The standard library has adopted -//! the necessary improvements for this to be possible as part of [RFC 2504]. -//! -//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md -//! -//! ## Comparison to thiserror -//! -//! Use `eyre` if you don't think you'll do anything with an error other than -//! report it. This is common in application code. Use `thiserror` if you think -//! you need an error type that can be handled via match or reported. This is -//! common in library crates where you don't know how your users will handle -//! your errors. -//! -//! [thiserror]: https://github.com/dtolnay/thiserror -//! -//! ## Compatibility with `anyhow` -//! -//! This crate does its best to be usable as a drop in replacement of `anyhow` and -//! vice-versa by re-exporting all of the renamed APIs with the names used in -//! `anyhow`, though there are some differences still. -//! -//! #### `Context` and `Option` -//! -//! As part of renaming `Context` to `WrapErr` we also intentionally do not -//! implement `WrapErr` for `Option`. This decision was made because `wrap_err` -//! implies that you're creating a new error that saves the old error as its -//! `source`. With `Option` there is no source error to wrap, so `wrap_err` ends up -//! being somewhat meaningless. -//! -//! Instead `eyre` offers [`OptionExt::ok_or_eyre`] to yield _static_ errors from `None`, -//! and intends for users to use the combinator functions provided by -//! `std`, converting `Option`s to `Result`s, for _dynamic_ errors. -//! So where you would write this with -//! anyhow: -//! -//! ```rust -//! use anyhow::Context; -//! -//! let opt: Option<()> = None; -//! let result_static = opt.context("static error message"); -//! let result_dynamic = opt.with_context(|| format!("{} error message", "dynamic")); -//! ``` -//! -//! With `eyre` we want users to write: -//! -//! ```rust -//! use eyre::{eyre, OptionExt, Result}; -//! -//! # #[cfg(not(feature = "auto-install"))] -//! # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); -//! # -//! let opt: Option<()> = None; -//! let result_static: Result<()> = opt.ok_or_eyre("static error message"); -//! let result_dynamic: Result<()> = opt.ok_or_else(|| eyre!("{} error message", "dynamic")); -//! ``` -//! -//! **NOTE**: However, to help with porting we do provide a `ContextCompat` trait which -//! implements `context` for options which you can import to make existing -//! `.context` calls compile. -//! -//! [^1]: example and explanation of breakage -//! -//! [Report]: https://docs.rs/eyre/*/eyre/struct.Report.html -//! [`eyre::EyreHandler`]: https://docs.rs/eyre/*/eyre/trait.EyreHandler.html -//! [`eyre::WrapErr`]: https://docs.rs/eyre/*/eyre/trait.WrapErr.html -//! [`anyhow::Context`]: https://docs.rs/anyhow/*/anyhow/trait.Context.html -//! [`anyhow`]: https://github.com/dtolnay/anyhow -//! [`tracing_error::SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html -//! [`stable-eyre`]: https://github.com/eyre-rs/stable-eyre -//! [`color-eyre`]: https://github.com/eyre-rs/color-eyre -//! [`jane-eyre`]: https://github.com/yaahc/jane-eyre -//! [`simple-eyre`]: https://github.com/eyre-rs/simple-eyre -//! [`color-spantrace`]: https://github.com/eyre-rs/color-spantrace -//! [`color-backtrace`]: https://github.com/athre0z/color-backtrace -#![doc(html_root_url = "https://docs.rs/eyre/0.6.12")] -#![cfg_attr( - nightly, - feature(rustdoc_missing_doc_code_examples), - warn(rustdoc::missing_doc_code_examples) -)] -#![warn( - missing_debug_implementations, - missing_docs, - unsafe_op_in_unsafe_fn, - rust_2018_idioms, - unreachable_pub, - bad_style, - dead_code, - improper_ctypes, - non_shorthand_field_patterns, - no_mangle_generic_items, - overflowing_literals, - path_statements, - patterns_in_fns_without_body, - unconditional_recursion, - unused, - unused_allocation, - unused_comparisons, - unused_parens, - while_true -)] -#![cfg_attr(backtrace, feature(backtrace))] -#![cfg_attr(doc_cfg, feature(doc_cfg))] -#![allow( - clippy::needless_doctest_main, - clippy::new_ret_no_self, - clippy::wrong_self_convention -)] - -extern crate alloc; - -#[macro_use] -mod backtrace; -mod chain; -mod context; -mod error; -mod fmt; -mod kind; -mod macros; -mod option; -mod ptr; -mod wrapper; - -use crate::backtrace::Backtrace; -use crate::error::ErrorImpl; -use core::fmt::{Debug, Display}; - -use std::error::Error as StdError; - -pub use eyre as format_err; -/// Compatibility re-export of `eyre` for interop with `anyhow` -pub use eyre as anyhow; -use once_cell::sync::OnceCell; -use ptr::OwnedPtr; -#[doc(hidden)] -pub use DefaultHandler as DefaultContext; -#[doc(hidden)] -pub use EyreHandler as EyreContext; -#[doc(hidden)] -pub use Report as ErrReport; -/// Compatibility re-export of `Report` for interop with `anyhow` -pub use Report as Error; -/// Compatibility re-export of `WrapErr` for interop with `anyhow` -pub use WrapErr as Context; - -/// The core error reporting type of the library, a wrapper around a dynamic error reporting type. -/// -/// `Report` works a lot like `Box`, but with these -/// differences: -/// -/// - `Report` requires that the error is `Send`, `Sync`, and `'static`. -/// - `Report` guarantees that a backtrace is available, even if the underlying -/// error type does not provide one. -/// - `Report` is represented as a narrow pointer — exactly one word in -/// size instead of two. -/// -/// # Display representations -/// -/// When you print an error object using "{}" or to_string(), only the outermost underlying error -/// is printed, not any of the lower level causes. This is exactly as if you had called the Display -/// impl of the error from which you constructed your eyre::Report. -/// -/// ```console -/// Failed to read instrs from ./path/to/instrs.json -/// ``` -/// -/// To print causes as well using eyre's default formatting of causes, use the -/// alternate selector "{:#}". -/// -/// ```console -/// Failed to read instrs from ./path/to/instrs.json: No such file or directory (os error 2) -/// ``` -/// -/// The Debug format "{:?}" includes your backtrace if one was captured. Note -/// that this is the representation you get by default if you return an error -/// from `fn main` instead of printing it explicitly yourself. -/// -/// ```console -/// Error: Failed to read instrs from ./path/to/instrs.json -/// -/// Caused by: -/// No such file or directory (os error 2) -/// -/// Stack backtrace: -/// 0: ::ext_report -/// at /git/eyre/src/backtrace.rs:26 -/// 1: core::result::Result::map_err -/// at /git/rustc/src/libcore/result.rs:596 -/// 2: eyre::context:: for core::result::Result>::wrap_err_with -/// at /git/eyre/src/context.rs:58 -/// 3: testing::main -/// at src/main.rs:5 -/// 4: std::rt::lang_start -/// at /git/rustc/src/libstd/rt.rs:61 -/// 5: main -/// 6: __libc_start_main -/// 7: _start -/// ``` -/// -/// To see a conventional struct-style Debug representation, use "{:#?}". -/// -/// ```console -/// Error { -/// msg: "Failed to read instrs from ./path/to/instrs.json", -/// source: Os { -/// code: 2, -/// kind: NotFound, -/// message: "No such file or directory", -/// }, -/// } -/// ``` -/// -/// If none of the built-in representations are appropriate and you would prefer -/// to render the error and its cause chain yourself, it can be done by defining -/// your own [`EyreHandler`] and [`hook`] to use it. -/// -/// [`EyreHandler`]: trait.EyreHandler.html -/// [`hook`]: fn.set_hook.html -#[must_use] -pub struct Report { - inner: OwnedPtr>, -} - -type ErrorHook = - Box Box + Sync + Send + 'static>; - -static HOOK: OnceCell = OnceCell::new(); - -/// Error indicating that `set_hook` was unable to install the provided ErrorHook -#[derive(Debug, Clone, Copy)] -pub struct InstallError; - -impl core::fmt::Display for InstallError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_str("cannot install provided ErrorHook, a hook has already been installed") - } -} - -impl StdError for InstallError {} - -/// Install the provided error hook for constructing EyreHandlers when converting -/// Errors to Reports -/// -/// # Details -/// -/// To customize the format and content of error reports from `eyre` you must -/// first define a new `EyreHandler` type to capture and store the extra context -/// and to define the format of how to display the chain of errors and this -/// stored context. Once this type has been defined you must also define a global -/// hook used to construct these handlers whenever `Report`s are constructed. -/// -/// # Examples -/// -/// ```rust,should_panic -/// use backtrace::Backtrace; -/// use eyre::EyreHandler; -/// use std::error::Error; -/// use std::{fmt, iter}; -/// -/// fn main() -> eyre::Result<()> { -/// // Install our custom eyre report hook for constructing our custom Handlers -/// install().unwrap(); -/// -/// // construct a report with, hopefully, our custom handler! -/// let mut report = eyre::eyre!("hello from custom error town!"); -/// -/// // manually set the custom msg for this report after it has been constructed -/// if let Some(handler) = report.handler_mut().downcast_mut::() { -/// handler.custom_msg = Some("you're the best users, you know that right???"); -/// } -/// -/// // print that shit!! -/// Err(report) -/// } -/// -/// // define a handler that captures backtraces unless told not to -/// fn install() -> Result<(), impl Error> { -/// let capture_backtrace = std::env::var("RUST_BACKWARDS_TRACE") -/// .map(|val| val != "0") -/// .unwrap_or(true); -/// -/// let hook = Hook { capture_backtrace }; -/// -/// eyre::set_hook(Box::new(move |e| Box::new(hook.make_handler(e)))) -/// } -/// -/// struct Hook { -/// capture_backtrace: bool, -/// } -/// -/// impl Hook { -/// fn make_handler(&self, _error: &(dyn Error + 'static)) -> Handler { -/// let backtrace = if self.capture_backtrace { -/// Some(Backtrace::new()) -/// } else { -/// None -/// }; -/// -/// Handler { -/// backtrace, -/// custom_msg: None, -/// } -/// } -/// } -/// -/// struct Handler { -/// // custom configured backtrace capture -/// backtrace: Option, -/// // customizable message payload associated with reports -/// custom_msg: Option<&'static str>, -/// } -/// -/// impl EyreHandler for Handler { -/// fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result { -/// if f.alternate() { -/// return fmt::Debug::fmt(error, f); -/// } -/// -/// let errors = iter::successors(Some(error), |error| (*error).source()); -/// -/// for (ind, error) in errors.enumerate() { -/// write!(f, "\n{:>4}: {}", ind, error)?; -/// } -/// -/// if let Some(backtrace) = self.backtrace.as_ref() { -/// writeln!(f, "\n\nBacktrace:\n{:?}", backtrace)?; -/// } -/// -/// if let Some(msg) = self.custom_msg.as_ref() { -/// writeln!(f, "\n\n{}", msg)?; -/// } -/// -/// Ok(()) -/// } -/// } -/// ``` -pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> { - HOOK.set(hook).map_err(|_| InstallError) -} - -#[cfg_attr(track_caller, track_caller)] -#[cfg_attr(not(track_caller), allow(unused_mut))] -fn capture_handler(error: &(dyn StdError + 'static)) -> Box { - #[cfg(not(feature = "auto-install"))] - let hook = HOOK - .get() - .expect("a handler must always be installed if the `auto-install` feature is disabled") - .as_ref(); - - #[cfg(feature = "auto-install")] - let hook = HOOK - .get_or_init(|| Box::new(DefaultHandler::default_with)) - .as_ref(); - - let mut handler = hook(error); - - #[cfg(track_caller)] - { - handler.track_caller(std::panic::Location::caller()) - } - - handler -} - -impl dyn EyreHandler { - /// - pub fn is(&self) -> bool { - // Get `TypeId` of the type this function is instantiated with. - let t = core::any::TypeId::of::(); - - // Get `TypeId` of the type in the trait object (`self`). - let concrete = self.type_id(); - - // Compare both `TypeId`s on equality. - t == concrete - } - - /// - pub fn downcast_ref(&self) -> Option<&T> { - if self.is::() { - unsafe { Some(&*(self as *const dyn EyreHandler as *const T)) } - } else { - None - } - } - - /// - pub fn downcast_mut(&mut self) -> Option<&mut T> { - if self.is::() { - unsafe { Some(&mut *(self as *mut dyn EyreHandler as *mut T)) } - } else { - None - } - } -} - -/// Error Report Handler trait for customizing `eyre::Report` -pub trait EyreHandler: core::any::Any + Send + Sync { - /// Define the report format - /// - /// Used to override the report format of `eyre::Report` - /// - /// # Example - /// - /// ```rust - /// use backtrace::Backtrace; - /// use eyre::EyreHandler; - /// use eyre::Chain; - /// use std::error::Error; - /// use indenter::indented; - /// - /// pub struct Handler { - /// backtrace: Backtrace, - /// } - /// - /// impl EyreHandler for Handler { - /// fn debug( - /// &self, - /// error: &(dyn Error + 'static), - /// f: &mut core::fmt::Formatter<'_>, - /// ) -> core::fmt::Result { - /// use core::fmt::Write as _; - /// - /// if f.alternate() { - /// return core::fmt::Debug::fmt(error, f); - /// } - /// - /// write!(f, "{}", error)?; - /// - /// if let Some(cause) = error.source() { - /// write!(f, "\n\nCaused by:")?; - /// let multiple = cause.source().is_some(); - /// - /// for (n, error) in Chain::new(cause).enumerate() { - /// writeln!(f)?; - /// if multiple { - /// write!(indented(f).ind(n), "{}", error)?; - /// } else { - /// write!(indented(f), "{}", error)?; - /// } - /// } - /// } - /// - /// let backtrace = &self.backtrace; - /// write!(f, "\n\nStack backtrace:\n{:?}", backtrace)?; - /// - /// Ok(()) - /// } - /// } - /// ``` - fn debug( - &self, - error: &(dyn StdError + 'static), - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result; - - /// Override for the `Display` format - fn display( - &self, - error: &(dyn StdError + 'static), - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - write!(f, "{}", error)?; - - if f.alternate() { - for cause in crate::chain::Chain::new(error).skip(1) { - write!(f, ": {}", cause)?; - } - } - - Result::Ok(()) - } - - /// Store the location of the caller who constructed this error report - #[allow(unused_variables)] - fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {} -} - -/// The default provided error report handler for `eyre::Report`. -/// -/// On nightly this supports conditionally capturing a `std::backtrace::Backtrace` if the source -/// error did not already capture one. -#[allow(dead_code)] -pub struct DefaultHandler { - backtrace: Option, - #[cfg(track_caller)] - location: Option<&'static std::panic::Location<'static>>, -} - -impl DefaultHandler { - /// Manual hook which constructs `DefaultHandler`s. - /// - /// # Details - /// - /// When supplied to the `set_hook` function, `default_with` will cause `eyre::Report` to use - /// `DefaultHandler` as the error report handler. - /// - /// If the `auto-install` feature is enabled, and a user-provided hook for constructing - /// `EyreHandlers` was not installed using `set_hook`, `DefaultHandler::default_with` - /// is automatically installed as the hook. - /// - /// # Example - /// - /// ```rust,should_panic - /// use eyre::{DefaultHandler, eyre, InstallError, Result, set_hook}; - /// - /// fn main() -> Result<()> { - /// install_default().expect("default handler inexplicably already installed"); - /// Err(eyre!("hello from default error city!")) - /// } - /// - /// fn install_default() -> Result<(), InstallError> { - /// set_hook(Box::new(DefaultHandler::default_with)) - /// } - /// - /// ``` - #[allow(unused_variables)] - #[cfg_attr(not(feature = "auto-install"), allow(dead_code))] - pub fn default_with(error: &(dyn StdError + 'static)) -> Box { - let backtrace = backtrace_if_absent!(error); - - Box::new(Self { - backtrace, - #[cfg(track_caller)] - location: None, - }) - } -} - -impl core::fmt::Debug for DefaultHandler { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("DefaultHandler") - .field( - "backtrace", - match &self.backtrace { - Some(_) => &"Some(Backtrace { ... })", - None => &"None", - }, - ) - .finish() - } -} - -impl EyreHandler for DefaultHandler { - fn debug( - &self, - error: &(dyn StdError + 'static), - f: &mut core::fmt::Formatter<'_>, - ) -> core::fmt::Result { - use core::fmt::Write as _; - - if f.alternate() { - return core::fmt::Debug::fmt(error, f); - } - - write!(f, "{}", error)?; - - if let Some(cause) = error.source() { - write!(f, "\n\nCaused by:")?; - let multiple = cause.source().is_some(); - for (n, error) in crate::chain::Chain::new(cause).enumerate() { - writeln!(f)?; - if multiple { - write!(indenter::indented(f).ind(n), "{}", error)?; - } else { - write!(indenter::indented(f), "{}", error)?; - } - } - } - - #[cfg(all(track_caller, feature = "track-caller"))] - { - if let Some(location) = self.location { - write!(f, "\n\nLocation:\n")?; - write!(indenter::indented(f), "{}", location)?; - } - } - - #[cfg(backtrace)] - { - use std::backtrace::BacktraceStatus; - - let backtrace = self - .backtrace - .as_ref() - .or_else(|| error.backtrace()) - .expect("backtrace capture failed"); - if let BacktraceStatus::Captured = backtrace.status() { - write!(f, "\n\nStack backtrace:\n{}", backtrace)?; - } - } - - Result::Ok(()) - } - - #[cfg(track_caller)] - fn track_caller(&mut self, location: &'static std::panic::Location<'static>) { - self.location = Some(location); - } -} - -/// Iterator of a chain of source errors. -/// -/// This type is the iterator returned by [`Report::chain`]. -/// -/// # Example -/// -/// ``` -/// use eyre::Report; -/// use std::io; -/// -/// pub fn underlying_io_error_kind(error: &Report) -> Option { -/// for cause in error.chain() { -/// if let Some(io_error) = cause.downcast_ref::() { -/// return Some(io_error.kind()); -/// } -/// } -/// None -/// } -/// ``` -#[derive(Clone)] -#[allow(missing_debug_implementations)] -pub struct Chain<'a> { - state: crate::chain::ChainState<'a>, -} - -/// type alias for `Result` -/// -/// This is a reasonable return type to use throughout your application but also for `fn main`; if -/// you do, failures will be printed along with a backtrace if one was captured. -/// -/// `eyre::Result` may be used with one *or* two type parameters. -/// -/// ```rust -/// use eyre::Result; -/// -/// # const IGNORE: &str = stringify! { -/// fn demo1() -> Result {...} -/// // ^ equivalent to std::result::Result -/// -/// fn demo2() -> Result {...} -/// // ^ equivalent to std::result::Result -/// # }; -/// ``` -/// -/// # Example -/// -/// ``` -/// # pub trait Deserialize {} -/// # -/// # mod serde_json { -/// # use super::Deserialize; -/// # use std::io; -/// # -/// # pub fn from_str(json: &str) -> io::Result { -/// # unimplemented!() -/// # } -/// # } -/// # -/// # #[derive(Debug)] -/// # struct ClusterMap; -/// # -/// # impl Deserialize for ClusterMap {} -/// # -/// use eyre::Result; -/// -/// fn main() -> Result<()> { -/// # return Ok(()); -/// let config = std::fs::read_to_string("cluster.json")?; -/// let map: ClusterMap = serde_json::from_str(&config)?; -/// println!("cluster info: {:#?}", map); -/// Ok(()) -/// } -/// ``` -pub type Result = core::result::Result; - -/// Provides the `wrap_err` method for `Result`. -/// -/// This trait is sealed and cannot be implemented for types outside of -/// `eyre`. -/// -/// # Example -/// -/// ``` -/// use eyre::{WrapErr, Result}; -/// use std::fs; -/// use std::path::PathBuf; -/// -/// pub struct ImportantThing { -/// path: PathBuf, -/// } -/// -/// impl ImportantThing { -/// # const IGNORE: &'static str = stringify! { -/// pub fn detach(&mut self) -> Result<()> {...} -/// # }; -/// # fn detach(&mut self) -> Result<()> { -/// # unimplemented!() -/// # } -/// } -/// -/// pub fn do_it(mut it: ImportantThing) -> Result> { -/// it.detach().wrap_err("Failed to detach the important thing")?; -/// -/// let path = &it.path; -/// let content = fs::read(path) -/// .wrap_err_with(|| format!("Failed to read instrs from {}", path.display()))?; -/// -/// Ok(content) -/// } -/// ``` -/// -/// When printed, the outermost error would be printed first and the lower -/// level underlying causes would be enumerated below. -/// -/// ```console -/// Error: Failed to read instrs from ./path/to/instrs.json -/// -/// Caused by: -/// No such file or directory (os error 2) -/// ``` -/// -/// # Wrapping Types That Don't impl `Error` (e.g. `&str` and `Box`) -/// -/// Due to restrictions for coherence `Report` cannot impl `From` for types that don't impl -/// `Error`. Attempts to do so will give "this type might implement Error in the future" as an -/// error. As such, `wrap_err`, which uses `From` under the hood, cannot be used to wrap these -/// types. Instead we encourage you to use the combinators provided for `Result` in `std`/`core`. -/// -/// For example, instead of this: -/// -/// ```rust,compile_fail -/// use std::error::Error; -/// use eyre::{WrapErr, Report}; -/// -/// fn wrap_example(err: Result<(), Box>) -> Result<(), Report> { -/// err.wrap_err("saw a downstream error") -/// } -/// ``` -/// -/// We encourage you to write this: -/// -/// ```rust -/// use std::error::Error; -/// use eyre::{WrapErr, Report, eyre}; -/// -/// fn wrap_example(err: Result<(), Box>) -> Result<(), Report> { -/// err.map_err(|e| eyre!(e)).wrap_err("saw a downstream error") -/// } -/// ``` -/// -/// # Effect on downcasting -/// -/// After attaching a message of type `D` onto an error of type `E`, the resulting -/// `eyre::Report` may be downcast to `D` **or** to `E`. -/// -/// That is, in codebases that rely on downcasting, Eyre's wrap_err supports -/// both of the following use cases: -/// -/// - **Attaching messages whose type is insignificant onto errors whose type -/// is used in downcasts.** -/// -/// In other error libraries whose wrap_err is not designed this way, it can -/// be risky to introduce messages to existing code because new message might -/// break existing working downcasts. In Eyre, any downcast that worked -/// before adding the message will continue to work after you add a message, so -/// you should freely wrap errors wherever it would be helpful. -/// -/// ``` -/// # use eyre::bail; -/// # use thiserror::Error; -/// # -/// # #[derive(Error, Debug)] -/// # #[error("???")] -/// # struct SuspiciousError; -/// # -/// # fn helper() -> Result<()> { -/// # bail!(SuspiciousError); -/// # } -/// # -/// use eyre::{WrapErr, Result}; -/// -/// fn do_it() -> Result<()> { -/// helper().wrap_err("Failed to complete the work")?; -/// # const IGNORE: &str = stringify! { -/// ... -/// # }; -/// # unreachable!() -/// } -/// -/// fn main() { -/// # #[cfg(not(feature = "auto-install"))] -/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); -/// let err = do_it().unwrap_err(); -/// if let Some(e) = err.downcast_ref::() { -/// // If helper() returned SuspiciousError, this downcast will -/// // correctly succeed even with the message in between. -/// # return; -/// } -/// # panic!("expected downcast to succeed"); -/// } -/// ``` -/// -/// - **Attaching message whose type is used in downcasts onto errors whose -/// type is insignificant.** -/// -/// Some codebases prefer to use machine-readable messages to categorize -/// lower level errors in a way that will be actionable to higher levels of -/// the application. -/// -/// ``` -/// # use eyre::bail; -/// # use thiserror::Error; -/// # -/// # #[derive(Error, Debug)] -/// # #[error("???")] -/// # struct HelperFailed; -/// # -/// # fn helper() -> Result<()> { -/// # bail!("no such file or directory"); -/// # } -/// # -/// use eyre::{WrapErr, Result}; -/// -/// fn do_it() -> Result<()> { -/// helper().wrap_err(HelperFailed)?; -/// # const IGNORE: &str = stringify! { -/// ... -/// # }; -/// # unreachable!() -/// } -/// -/// fn main() { -/// # #[cfg(not(feature = "auto-install"))] -/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); -/// let err = do_it().unwrap_err(); -/// if let Some(e) = err.downcast_ref::() { -/// // If helper failed, this downcast will succeed because -/// // HelperFailed is the message that has been attached to -/// // that error. -/// # return; -/// } -/// # panic!("expected downcast to succeed"); -/// } -/// ``` -/// -/// # `wrap_err` vs `wrap_err_with` -/// -/// `wrap_err` incurs a runtime cost even in the non-error case because it requires eagerly -/// constructing the error object. `wrap_err_with` avoids this cost through lazy evaluation. This -/// cost is proportional to the cost of the currently installed [`EyreHandler`]'s creation step. -/// `wrap_err` is useful in cases where an constructed error object already exists. -pub trait WrapErr: context::private::Sealed { - /// Wrap the error value with a new adhoc error - #[cfg_attr(track_caller, track_caller)] - fn wrap_err(self, msg: D) -> Result - where - D: Display + Send + Sync + 'static; - - /// Wrap the error value with a new adhoc error that is evaluated lazily - /// only once an error does occur. - #[cfg_attr(track_caller, track_caller)] - fn wrap_err_with(self, f: F) -> Result - where - D: Display + Send + Sync + 'static, - F: FnOnce() -> D; - - /// Compatibility re-export of wrap_err for interop with `anyhow` - #[cfg_attr(track_caller, track_caller)] - fn context(self, msg: D) -> Result - where - D: Display + Send + Sync + 'static; - - /// Compatibility re-export of wrap_err_with for interop with `anyhow` - #[cfg_attr(track_caller, track_caller)] - fn with_context(self, f: F) -> Result - where - D: Display + Send + Sync + 'static, - F: FnOnce() -> D; -} - -/// Provides the [`ok_or_eyre`][OptionExt::ok_or_eyre] method for [`Option`]. -/// -/// This trait is sealed and cannot be implemented for types outside of -/// `eyre`. -/// -/// # Example -/// -/// ``` -/// # #[cfg(not(feature = "auto-install"))] -/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); -/// use eyre::OptionExt; -/// -/// let option: Option<()> = None; -/// -/// let result = option.ok_or_eyre("static str error"); -/// -/// assert_eq!(result.unwrap_err().to_string(), "static str error"); -/// ``` -/// -/// # `ok_or_eyre` vs `ok_or_else` -/// -/// If string interpolation is required for the generated [report][Report], -/// use [`ok_or_else`][Option::ok_or_else] instead, -/// invoking [`eyre!`] to perform string interpolation: -/// -/// ``` -/// # #[cfg(not(feature = "auto-install"))] -/// # eyre::set_hook(Box::new(eyre::DefaultHandler::default_with)).unwrap(); -/// use eyre::eyre; -/// -/// let option: Option<()> = None; -/// -/// let result = option.ok_or_else(|| eyre!("{} error", "dynamic")); -/// -/// assert_eq!(result.unwrap_err().to_string(), "dynamic error"); -/// ``` -/// -/// `ok_or_eyre` incurs no runtime cost, as the error object -/// is constructed from the provided static argument -/// only in the `None` case. -pub trait OptionExt: context::private::Sealed { - /// Transform the [`Option`] into a [`Result`], - /// mapping [`Some(v)`][Option::Some] to [`Ok(v)`][Result::Ok] - /// and [`None`] to [`Report`]. - /// - /// `ok_or_eyre` allows for eyre [`Report`] error objects - /// to be lazily created from static messages in the `None` case. - /// - /// For dynamic error messages, use [`ok_or_else`][Option::ok_or_else], - /// invoking [`eyre!`] in the closure to perform string interpolation. - fn ok_or_eyre(self, message: M) -> crate::Result - where - M: Debug + Display + Send + Sync + 'static; -} - -/// Provides the `context` method for `Option` when porting from `anyhow` -/// -/// This trait is sealed and cannot be implemented for types outside of -/// `eyre`. -/// -/// ## Why Doesn't `Eyre` impl `WrapErr` for `Option`? -/// -/// `eyre` doesn't impl `WrapErr` for `Option` because `wrap_err` implies that you're creating a -/// new error that saves the previous error as its `source`. Calling `wrap_err` on an `Option` is -/// meaningless because there is no source error. `anyhow` avoids this issue by using a different -/// mental model where you're adding "context" to an error, though this not a mental model for -/// error handling that `eyre` agrees with. -/// -/// Instead, `eyre` encourages users to think of each error as distinct, where the previous error -/// is the context being saved by the new error, which is backwards compared to anyhow's model. In -/// this model you're encouraged to use combinators provided by `std` for `Option` to convert an -/// option to a `Result` -/// -/// # Example -/// -/// Instead of: -/// -/// ```rust -/// use eyre::ContextCompat; -/// -/// fn get_thing(mut things: impl Iterator) -> eyre::Result { -/// things -/// .find(|&thing| thing == 42) -/// .context("the thing wasnt in the list") -/// } -/// ``` -/// -/// We encourage you to use this: -/// -/// ```rust -/// use eyre::eyre; -/// -/// fn get_thing(mut things: impl Iterator) -> eyre::Result { -/// things -/// .find(|&thing| thing == 42) -/// .ok_or_else(|| eyre!("the thing wasnt in the list")) -/// } -/// ``` -pub trait ContextCompat: context::private::Sealed { - /// Compatibility version of `wrap_err` for creating new errors with new source on `Option` - /// when porting from `anyhow` - #[cfg_attr(track_caller, track_caller)] - fn context(self, msg: D) -> Result - where - D: Display + Send + Sync + 'static; - - /// Compatibility version of `wrap_err_with` for creating new errors with new source on `Option` - /// when porting from `anyhow` - #[cfg_attr(track_caller, track_caller)] - fn with_context(self, f: F) -> Result - where - D: Display + Send + Sync + 'static, - F: FnOnce() -> D; - - /// Compatibility re-export of `context` for porting from `anyhow` to `eyre` - #[cfg_attr(track_caller, track_caller)] - fn wrap_err(self, msg: D) -> Result - where - D: Display + Send + Sync + 'static; - - /// Compatibility re-export of `with_context` for porting from `anyhow` to `eyre` - #[cfg_attr(track_caller, track_caller)] - fn wrap_err_with(self, f: F) -> Result - where - D: Display + Send + Sync + 'static, - F: FnOnce() -> D; -} - -/// Equivalent to Ok::<_, eyre::Error>(value). -/// -/// This simplifies creation of an eyre::Result in places where type inference -/// cannot deduce the `E` type of the result — without needing to write -/// `Ok::<_, eyre::Error>(value)`. -/// -/// One might think that `eyre::Result::Ok(value)` would work in such cases -/// but it does not. -/// -/// ```console -/// error[E0282]: type annotations needed for `std::result::Result` -/// --> src/main.rs:11:13 -/// | -/// 11 | let _ = eyre::Result::Ok(1); -/// | - ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result` -/// | | -/// | consider giving this pattern the explicit type `std::result::Result`, where the type parameter `E` is specified -/// ``` -#[allow(non_snake_case)] -pub fn Ok(t: T) -> Result { - Result::Ok(t) -} - -// Not public API. Referenced by macro-generated code. -#[doc(hidden)] -pub mod private { - use crate::Report; - use alloc::fmt; - use core::fmt::{Arguments, Debug, Display}; - - pub use alloc::format; - pub use core::format_args; - pub use core::result::Result::Err; - - #[doc(hidden)] - pub mod kind { - pub use crate::kind::{AdhocKind, TraitKind}; - - pub use crate::kind::BoxedKind; - } - - #[cfg_attr(track_caller, track_caller)] - pub fn new_adhoc(message: M) -> Report - where - M: Display + Debug + Send + Sync + 'static, - { - Report::from_adhoc(message) - } - - #[doc(hidden)] - #[cold] - #[cfg_attr(track_caller, track_caller)] - pub fn format_err(args: Arguments<'_>) -> Report { - #[cfg(eyre_no_fmt_arguments_as_str)] - let fmt_arguments_as_str: Option<&str> = None; - #[cfg(not(eyre_no_fmt_arguments_as_str))] - let fmt_arguments_as_str = args.as_str(); - - if let Some(message) = fmt_arguments_as_str { - // eyre!("literal"), can downcast to &'static str - Report::msg(message) - } else { - // eyre!("interpolate {var}"), can downcast to String - Report::msg(fmt::format(args)) - } - } -} diff --git a/third-party/vendor/eyre/src/macros.rs b/third-party/vendor/eyre/src/macros.rs deleted file mode 100644 index 032f82a2..00000000 --- a/third-party/vendor/eyre/src/macros.rs +++ /dev/null @@ -1,170 +0,0 @@ -/// Return early with an error. -/// -/// This macro is equivalent to `return Err(eyre!())`. -/// -/// # Example -/// -/// ``` -/// # use eyre::{bail, Result}; -/// # -/// # fn has_permission(user: usize, resource: usize) -> bool { -/// # true -/// # } -/// # -/// # fn main() -> Result<()> { -/// # let user = 0; -/// # let resource = 0; -/// # -/// if !has_permission(user, resource) { -/// bail!("permission denied for accessing {}", resource); -/// } -/// # Ok(()) -/// # } -/// ``` -/// -/// ``` -/// # use eyre::{bail, Result}; -/// # use thiserror::Error; -/// # -/// # const MAX_DEPTH: usize = 1; -/// # -/// #[derive(Error, Debug)] -/// enum ScienceError { -/// #[error("recursion limit exceeded")] -/// RecursionLimitExceeded, -/// # #[error("...")] -/// # More = (stringify! { -/// ... -/// # }, 1).1, -/// } -/// -/// # fn main() -> Result<()> { -/// # let depth = 0; -/// # let err: &'static dyn std::error::Error = &ScienceError::RecursionLimitExceeded; -/// # -/// if depth > MAX_DEPTH { -/// bail!(ScienceError::RecursionLimitExceeded); -/// } -/// # Ok(()) -/// # } -/// ``` -#[macro_export] -macro_rules! bail { - ($msg:literal $(,)?) => { - return $crate::private::Err($crate::eyre!($msg)); - }; - ($err:expr $(,)?) => { - return $crate::private::Err($crate::eyre!($err)); - }; - ($fmt:expr, $($arg:tt)*) => { - return $crate::private::Err($crate::eyre!($fmt, $($arg)*)); - }; -} - -/// Return early with an error if a condition is not satisfied. -/// -/// This macro is equivalent to `if !$cond { return Err(eyre!()); }`. -/// -/// Analogously to `assert!`, `ensure!` takes a condition and exits the function -/// if the condition fails. Unlike `assert!`, `ensure!` returns an `eyre::Result` -/// rather than panicking. -/// -/// # Example -/// -/// ``` -/// # use eyre::{ensure, Result}; -/// # -/// # fn main() -> Result<()> { -/// # let user = 0; -/// # -/// ensure!(user == 0, "only user 0 is allowed"); -/// # Ok(()) -/// # } -/// ``` -/// -/// ``` -/// # use eyre::{ensure, Result}; -/// # use thiserror::Error; -/// # -/// # const MAX_DEPTH: usize = 1; -/// # -/// #[derive(Error, Debug)] -/// enum ScienceError { -/// #[error("recursion limit exceeded")] -/// RecursionLimitExceeded, -/// # #[error("...")] -/// # More = (stringify! { -/// ... -/// # }, 1).1, -/// } -/// -/// # fn main() -> Result<()> { -/// # let depth = 0; -/// # -/// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded); -/// # Ok(()) -/// # } -/// ``` -#[macro_export] -macro_rules! ensure { - ($cond:expr $(,)?) => { - if !$cond { - $crate::ensure!($cond, concat!("Condition failed: `", stringify!($cond), "`")) - } - }; - ($cond:expr, $msg:literal $(,)?) => { - if !$cond { - return $crate::private::Err($crate::eyre!($msg)); - } - }; - ($cond:expr, $err:expr $(,)?) => { - if !$cond { - return $crate::private::Err($crate::eyre!($err)); - } - }; - ($cond:expr, $fmt:expr, $($arg:tt)*) => { - if !$cond { - return $crate::private::Err($crate::eyre!($fmt, $($arg)*)); - } - }; -} - -/// Construct an ad-hoc error from a string. -/// -/// This evaluates to a `Report`. It can take either just a string, or a format -/// string with arguments. It also can take any custom type which implements -/// `Debug` and `Display`. -/// -/// # Example -/// -/// ``` -/// # type V = (); -/// # -/// use eyre::{eyre, Result}; -/// -/// fn lookup(key: &str) -> Result { -/// if key.len() != 16 { -/// return Err(eyre!("key length must be 16 characters, got {:?}", key)); -/// } -/// -/// // ... -/// # Ok(()) -/// } -/// ``` -#[macro_export] -macro_rules! eyre { - ($msg:literal $(,)?) => ({ - let error = $crate::private::format_err($crate::private::format_args!($msg)); - error - }); - ($err:expr $(,)?) => ({ - use $crate::private::kind::*; - let error = match $err { - error => (&error).eyre_kind().new(error), - }; - error - }); - ($fmt:expr, $($arg:tt)*) => { - $crate::private::new_adhoc($crate::private::format!($fmt, $($arg)*)) - }; -} diff --git a/third-party/vendor/eyre/src/option.rs b/third-party/vendor/eyre/src/option.rs deleted file mode 100644 index 881222ad..00000000 --- a/third-party/vendor/eyre/src/option.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::OptionExt; -use core::fmt::{Debug, Display}; - -impl OptionExt for Option { - #[track_caller] - fn ok_or_eyre(self, message: M) -> crate::Result - where - M: Debug + Display + Send + Sync + 'static, - { - match self { - Some(ok) => Ok(ok), - None => Err(crate::Report::msg(message)), - } - } -} diff --git a/third-party/vendor/eyre/src/ptr.rs b/third-party/vendor/eyre/src/ptr.rs deleted file mode 100644 index 3d118e51..00000000 --- a/third-party/vendor/eyre/src/ptr.rs +++ /dev/null @@ -1,149 +0,0 @@ -use std::{marker::PhantomData, ptr::NonNull}; - -/// An owned pointer -/// -/// **NOTE**: Does not deallocate when dropped -pub(crate) struct OwnedPtr { - ptr: NonNull, -} - -impl Copy for OwnedPtr {} - -impl Clone for OwnedPtr { - fn clone(&self) -> Self { - *self - } -} - -unsafe impl Send for OwnedPtr where T: Send {} -unsafe impl Sync for OwnedPtr where T: Send {} - -impl OwnedPtr { - pub(crate) fn new(value: T) -> Self { - Self::from_boxed(Box::new(value)) - } - - pub(crate) fn from_boxed(boxed: Box) -> Self { - // Safety: `Box::into_raw` is guaranteed to be non-null - Self { - ptr: unsafe { NonNull::new_unchecked(Box::into_raw(boxed)) }, - } - } - - /// Convert the pointer to another type - pub(crate) fn cast(self) -> OwnedPtr { - OwnedPtr { - ptr: self.ptr.cast(), - } - } - - /// Context the pointer into a Box - /// - /// # Safety - /// - /// Dropping the Box will deallocate a layout of `T` and run the destructor of `T`. - /// - /// A cast pointer must therefore be cast back to the original type before calling this method. - pub(crate) unsafe fn into_box(self) -> Box { - unsafe { Box::from_raw(self.ptr.as_ptr()) } - } - - pub(crate) const fn as_ref(&self) -> RefPtr<'_, T> { - RefPtr { - ptr: self.ptr, - _marker: PhantomData, - } - } - - pub(crate) fn as_mut(&mut self) -> MutPtr<'_, T> { - MutPtr { - ptr: self.ptr, - _marker: PhantomData, - } - } -} - -/// Convenience lifetime annotated mutable pointer which facilitates returning an inferred lifetime -/// in a `fn` pointer. -pub(crate) struct RefPtr<'a, T: ?Sized> { - pub(crate) ptr: NonNull, - _marker: PhantomData<&'a T>, -} - -/// Safety: RefPtr indicates a shared reference to a value and as such exhibits the same Send + -/// Sync behavior of &'a T -unsafe impl<'a, T: ?Sized> Send for RefPtr<'a, T> where &'a T: Send {} -unsafe impl<'a, T: ?Sized> Sync for RefPtr<'a, T> where &'a T: Sync {} - -impl<'a, T: ?Sized> Copy for RefPtr<'a, T> {} -impl<'a, T: ?Sized> Clone for RefPtr<'a, T> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a, T: ?Sized> RefPtr<'a, T> { - pub(crate) fn new(ptr: &'a T) -> Self { - Self { - ptr: NonNull::from(ptr), - _marker: PhantomData, - } - } - - /// Convert the pointer to another type - pub(crate) fn cast(self) -> RefPtr<'a, U> { - RefPtr { - ptr: self.ptr.cast(), - _marker: PhantomData, - } - } - - /// Returns a shared reference to the owned value - /// - /// # Safety - /// - /// See: [`NonNull::as_ref`] - #[inline] - pub(crate) unsafe fn as_ref(&self) -> &'a T { - unsafe { self.ptr.as_ref() } - } -} - -/// Convenience lifetime annotated mutable pointer which facilitates returning an inferred lifetime -/// in a `fn` pointer. -pub(crate) struct MutPtr<'a, T: ?Sized> { - pub(crate) ptr: NonNull, - _marker: PhantomData<&'a mut T>, -} - -/// Safety: RefPtr indicates an exclusive reference to a value and as such exhibits the same Send + -/// Sync behavior of &'a mut T -unsafe impl<'a, T: ?Sized> Send for MutPtr<'a, T> where &'a mut T: Send {} -unsafe impl<'a, T: ?Sized> Sync for MutPtr<'a, T> where &'a mut T: Sync {} - -impl<'a, T: ?Sized> Copy for MutPtr<'a, T> {} -impl<'a, T: ?Sized> Clone for MutPtr<'a, T> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a, T: ?Sized> MutPtr<'a, T> { - /// Convert the pointer to another type - pub(crate) fn cast(self) -> MutPtr<'a, U> { - MutPtr { - ptr: self.ptr.cast(), - _marker: PhantomData, - } - } - - /// Returns a mutable reference to the owned value with the lifetime decoupled from self - /// - /// # Safety - /// - /// See: [`NonNull::as_mut`] - #[inline] - pub(crate) unsafe fn into_mut(mut self) -> &'a mut T { - unsafe { self.ptr.as_mut() } - } -} diff --git a/third-party/vendor/eyre/src/wrapper.rs b/third-party/vendor/eyre/src/wrapper.rs deleted file mode 100644 index b4da68ab..00000000 --- a/third-party/vendor/eyre/src/wrapper.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::StdError; -use core::fmt::{self, Debug, Display}; - -#[repr(transparent)] -pub(crate) struct DisplayError(pub(crate) M); - -#[repr(transparent)] -/// Wraps a Debug + Display type as an error. -/// -/// Its Debug and Display impls are the same as the wrapped type. -pub(crate) struct MessageError(pub(crate) M); - -pub(crate) struct NoneError; - -impl Debug for DisplayError -where - M: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.0, f) - } -} - -impl Display for DisplayError -where - M: Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.0, f) - } -} - -impl StdError for DisplayError where M: Display + 'static {} - -impl Debug for MessageError -where - M: Display + Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&self.0, f) - } -} - -impl Display for MessageError -where - M: Display + Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.0, f) - } -} - -impl StdError for MessageError where M: Display + Debug + 'static {} - -impl Debug for NoneError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt("Option was None", f) - } -} - -impl Display for NoneError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt("Option was None", f) - } -} - -impl StdError for NoneError {} - -#[repr(transparent)] -pub(crate) struct BoxedError(pub(crate) Box); - -impl Debug for BoxedError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&self.0, f) - } -} - -impl Display for BoxedError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.0, f) - } -} - -impl StdError for BoxedError { - #[cfg(backtrace)] - fn backtrace(&self) -> Option<&crate::backtrace::Backtrace> { - self.0.backtrace() - } - - fn source(&self) -> Option<&(dyn StdError + 'static)> { - self.0.source() - } -} diff --git a/third-party/vendor/eyre/tests/common/mod.rs b/third-party/vendor/eyre/tests/common/mod.rs deleted file mode 100644 index 08ae5045..00000000 --- a/third-party/vendor/eyre/tests/common/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![allow(dead_code)] - -use eyre::{bail, set_hook, DefaultHandler, InstallError, Result}; -use once_cell::sync::OnceCell; -use std::io; - -pub fn bail_literal() -> Result<()> { - bail!("oh no!"); -} - -pub fn bail_fmt() -> Result<()> { - bail!("{} {}!", "oh", "no"); -} - -pub fn bail_error() -> Result<()> { - bail!(io::Error::new(io::ErrorKind::Other, "oh no!")); -} - -// Tests are multithreaded- use OnceCell to install hook once if auto-install -// feature is disabled. -pub fn maybe_install_handler() -> Result<(), InstallError> { - static INSTALLER: OnceCell> = OnceCell::new(); - - if cfg!(not(feature = "auto-install")) { - *INSTALLER.get_or_init(|| set_hook(Box::new(DefaultHandler::default_with))) - } else { - Ok(()) - } -} diff --git a/third-party/vendor/eyre/tests/compiletest.rs b/third-party/vendor/eyre/tests/compiletest.rs deleted file mode 100644 index 7974a624..00000000 --- a/third-party/vendor/eyre/tests/compiletest.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[rustversion::attr(not(nightly), ignore)] -#[cfg_attr(miri, ignore)] -#[test] -fn ui() { - let t = trybuild::TestCases::new(); - t.compile_fail("tests/ui/*.rs"); -} diff --git a/third-party/vendor/eyre/tests/drop/mod.rs b/third-party/vendor/eyre/tests/drop/mod.rs deleted file mode 100644 index 6f828ccf..00000000 --- a/third-party/vendor/eyre/tests/drop/mod.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::error::Error as StdError; -use std::fmt::{self, Display}; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::SeqCst; -use std::sync::Arc; - -#[derive(Debug)] -pub struct Flag { - atomic: Arc, -} - -impl Flag { - pub fn new() -> Self { - Flag { - atomic: Arc::new(AtomicBool::new(false)), - } - } - - pub fn get(&self) -> bool { - self.atomic.load(SeqCst) - } -} - -#[derive(Debug)] -pub struct DetectDrop { - has_dropped: Flag, - label: &'static str, -} - -impl DetectDrop { - pub fn new(label: &'static str, has_dropped: &Flag) -> Self { - DetectDrop { - label, - has_dropped: Flag { - atomic: Arc::clone(&has_dropped.atomic), - }, - } - } -} - -impl StdError for DetectDrop {} - -impl Display for DetectDrop { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "oh no!") - } -} - -impl Drop for DetectDrop { - fn drop(&mut self) { - eprintln!("Dropping {}", self.label); - let already_dropped = self.has_dropped.atomic.swap(true, SeqCst); - assert!(!already_dropped); - } -} diff --git a/third-party/vendor/eyre/tests/test_autotrait.rs b/third-party/vendor/eyre/tests/test_autotrait.rs deleted file mode 100644 index d31756e1..00000000 --- a/third-party/vendor/eyre/tests/test_autotrait.rs +++ /dev/null @@ -1,13 +0,0 @@ -use eyre::Report; - -#[test] -fn test_send() { - fn assert_send() {} - assert_send::(); -} - -#[test] -fn test_sync() { - fn assert_sync() {} - assert_sync::(); -} diff --git a/third-party/vendor/eyre/tests/test_boxed.rs b/third-party/vendor/eyre/tests/test_boxed.rs deleted file mode 100644 index 20bdbfae..00000000 --- a/third-party/vendor/eyre/tests/test_boxed.rs +++ /dev/null @@ -1,66 +0,0 @@ -mod common; - -use self::common::maybe_install_handler; -use eyre::{eyre, Report}; -use std::error::Error as StdError; -use std::io; -use thiserror::Error; - -#[derive(Error, Debug)] -#[error("outer")] -struct MyError { - source: io::Error, -} - -#[test] -fn test_boxed_str() { - maybe_install_handler().unwrap(); - - let error = Box::::from("oh no!"); - let error: Report = eyre!(error); - assert_eq!("oh no!", error.to_string()); - assert_eq!( - "oh no!", - error - .downcast_ref::>() - .unwrap() - .to_string() - ); -} - -#[test] -fn test_boxed_thiserror() { - maybe_install_handler().unwrap(); - - let error = MyError { - source: io::Error::new(io::ErrorKind::Other, "oh no!"), - }; - let error: Report = eyre!(error); - assert_eq!("oh no!", error.source().unwrap().to_string()); -} - -#[test] -fn test_boxed_eyre() { - maybe_install_handler().unwrap(); - - let error: Report = eyre!("oh no!").wrap_err("it failed"); - let error = eyre!(error); - assert_eq!("oh no!", error.source().unwrap().to_string()); -} - -#[test] -fn test_boxed_sources() { - maybe_install_handler().unwrap(); - - let error = MyError { - source: io::Error::new(io::ErrorKind::Other, "oh no!"), - }; - let error = Box::::from(error); - let error: Report = eyre!(error).wrap_err("it failed"); - assert_eq!("it failed", error.to_string()); - assert_eq!("outer", error.source().unwrap().to_string()); - assert_eq!( - "oh no!", - error.source().unwrap().source().unwrap().to_string() - ); -} diff --git a/third-party/vendor/eyre/tests/test_chain.rs b/third-party/vendor/eyre/tests/test_chain.rs deleted file mode 100644 index d6187448..00000000 --- a/third-party/vendor/eyre/tests/test_chain.rs +++ /dev/null @@ -1,54 +0,0 @@ -mod common; - -use self::common::maybe_install_handler; -use eyre::{eyre, Report}; - -fn error() -> Report { - eyre!({ 0 }).wrap_err(1).wrap_err(2).wrap_err(3) -} - -#[test] -fn test_iter() { - maybe_install_handler().unwrap(); - - let e = error(); - let mut chain = e.chain(); - assert_eq!("3", chain.next().unwrap().to_string()); - assert_eq!("2", chain.next().unwrap().to_string()); - assert_eq!("1", chain.next().unwrap().to_string()); - assert_eq!("0", chain.next().unwrap().to_string()); - assert!(chain.next().is_none()); - assert!(chain.next_back().is_none()); -} - -#[test] -fn test_rev() { - maybe_install_handler().unwrap(); - - let e = error(); - let mut chain = e.chain().rev(); - assert_eq!("0", chain.next().unwrap().to_string()); - assert_eq!("1", chain.next().unwrap().to_string()); - assert_eq!("2", chain.next().unwrap().to_string()); - assert_eq!("3", chain.next().unwrap().to_string()); - assert!(chain.next().is_none()); - assert!(chain.next_back().is_none()); -} - -#[test] -fn test_len() { - maybe_install_handler().unwrap(); - - let e = error(); - let mut chain = e.chain(); - assert_eq!(4, chain.len()); - assert_eq!("3", chain.next().unwrap().to_string()); - assert_eq!(3, chain.len()); - assert_eq!("0", chain.next_back().unwrap().to_string()); - assert_eq!(2, chain.len()); - assert_eq!("2", chain.next().unwrap().to_string()); - assert_eq!(1, chain.len()); - assert_eq!("1", chain.next_back().unwrap().to_string()); - assert_eq!(0, chain.len()); - assert!(chain.next().is_none()); -} diff --git a/third-party/vendor/eyre/tests/test_context.rs b/third-party/vendor/eyre/tests/test_context.rs deleted file mode 100644 index 93f229e4..00000000 --- a/third-party/vendor/eyre/tests/test_context.rs +++ /dev/null @@ -1,173 +0,0 @@ -mod common; -mod drop; - -use crate::common::maybe_install_handler; -use crate::drop::{DetectDrop, Flag}; -use eyre::{Report, Result, WrapErr}; -use std::fmt::{self, Display}; -use thiserror::Error; - -// https://github.com/dtolnay/eyre/issues/18 -#[test] -fn test_inference() -> Result<()> { - let x = "1"; - let y: u32 = x.parse().wrap_err("...")?; - assert_eq!(y, 1); - Ok(()) -} - -macro_rules! context_type { - ($name:ident) => { - #[derive(Debug)] - #[repr(C)] - struct $name { - _drop: DetectDrop, - message: &'static str, - } - - impl Display for $name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.message) - } - } - }; -} - -context_type!(HighLevel); -context_type!(MidLevel); - -#[derive(Error, Debug)] -#[error("{message}")] -#[repr(C)] -struct LowLevel { - message: &'static str, - drop: DetectDrop, -} - -struct Dropped { - low: Flag, - mid: Flag, - high: Flag, -} - -impl Dropped { - fn none(&self) -> bool { - !self.low.get() && !self.mid.get() && !self.high.get() - } - - fn all(&self) -> bool { - self.low.get() && self.mid.get() && self.high.get() - } -} - -fn make_chain() -> (Report, Dropped) { - let dropped = Dropped { - low: Flag::new(), - mid: Flag::new(), - high: Flag::new(), - }; - - let low = LowLevel { - message: "no such file or directory", - drop: DetectDrop::new("LowLevel", &dropped.low), - }; - - // impl Report for Result - let mid = Err::<(), LowLevel>(low) - .wrap_err(MidLevel { - message: "failed to load config", - _drop: DetectDrop::new("MidLevel", &dropped.mid), - }) - .unwrap_err(); - - // impl Report for Result - let high = Err::<(), Report>(mid) - .wrap_err(HighLevel { - message: "failed to start server", - _drop: DetectDrop::new("HighLevel", &dropped.high), - }) - .unwrap_err(); - - (high, dropped) -} - -#[test] -fn test_downcast_ref() { - maybe_install_handler().unwrap(); - - let (err, dropped) = make_chain(); - - assert!(!err.is::()); - assert!(err.downcast_ref::().is_none()); - - assert!(err.is::()); - let high = err.downcast_ref::().unwrap(); - assert_eq!(high.to_string(), "failed to start server"); - - assert!(err.is::()); - let mid = err.downcast_ref::().unwrap(); - assert_eq!(mid.to_string(), "failed to load config"); - - assert!(err.is::()); - let low = err.downcast_ref::().unwrap(); - assert_eq!(low.to_string(), "no such file or directory"); - - assert!(dropped.none()); - drop(err); - assert!(dropped.all()); -} - -#[test] -fn test_downcast_high() { - maybe_install_handler().unwrap(); - - let (err, dropped) = make_chain(); - - let err = err.downcast::().unwrap(); - assert!(!dropped.high.get()); - assert!(dropped.low.get() && dropped.mid.get()); - - drop(err); - assert!(dropped.all()); -} - -#[test] -fn test_downcast_mid() { - maybe_install_handler().unwrap(); - - let (err, dropped) = make_chain(); - - let err = err.downcast::().unwrap(); - assert!(!dropped.mid.get()); - assert!(dropped.low.get() && dropped.high.get()); - - drop(err); - assert!(dropped.all()); -} - -#[test] -fn test_downcast_low() { - maybe_install_handler().unwrap(); - - let (err, dropped) = make_chain(); - - let err = err.downcast::().unwrap(); - assert!(!dropped.low.get()); - assert!(dropped.mid.get() && dropped.high.get()); - - drop(err); - assert!(dropped.all()); -} - -#[test] -fn test_unsuccessful_downcast() { - maybe_install_handler().unwrap(); - - let (err, dropped) = make_chain(); - - let err = err.downcast::().unwrap_err(); - assert!(dropped.none()); - - drop(err); - assert!(dropped.all()); -} diff --git a/third-party/vendor/eyre/tests/test_context_access.rs b/third-party/vendor/eyre/tests/test_context_access.rs deleted file mode 100644 index 54e3da49..00000000 --- a/third-party/vendor/eyre/tests/test_context_access.rs +++ /dev/null @@ -1,13 +0,0 @@ -mod common; - -use crate::common::maybe_install_handler; - -#[test] -fn test_context() { - use eyre::{eyre, Report}; - - maybe_install_handler().unwrap(); - - let error: Report = eyre!("oh no!"); - let _ = error.context(); -} diff --git a/third-party/vendor/eyre/tests/test_convert.rs b/third-party/vendor/eyre/tests/test_convert.rs deleted file mode 100644 index e0f07f92..00000000 --- a/third-party/vendor/eyre/tests/test_convert.rs +++ /dev/null @@ -1,28 +0,0 @@ -mod common; -mod drop; - -use self::common::maybe_install_handler; -use self::drop::{DetectDrop, Flag}; -use eyre::{Report, Result}; -use std::error::Error as StdError; - -#[test] -fn test_convert() { - maybe_install_handler().unwrap(); - - let has_dropped = Flag::new(); - let error: Report = Report::new(DetectDrop::new("TestConvert", &has_dropped)); - let box_dyn = Box::::from(error); - assert_eq!("oh no!", box_dyn.to_string()); - drop(box_dyn); - assert!(has_dropped.get()); -} - -#[test] -fn test_question_mark() -> Result<(), Box> { - fn f() -> Result<()> { - Ok(()) - } - f()?; - Ok(()) -} diff --git a/third-party/vendor/eyre/tests/test_downcast.rs b/third-party/vendor/eyre/tests/test_downcast.rs deleted file mode 100644 index 6f662064..00000000 --- a/third-party/vendor/eyre/tests/test_downcast.rs +++ /dev/null @@ -1,148 +0,0 @@ -mod common; -mod drop; - -use self::common::*; -use self::drop::{DetectDrop, Flag}; -use eyre::Report; -use std::error::Error as StdError; -use std::fmt::{self, Display}; -use std::io; - -#[test] -fn test_downcast() { - maybe_install_handler().unwrap(); - - #[cfg(not(eyre_no_fmt_arguments_as_str))] - assert_eq!( - "oh no!", - bail_literal().unwrap_err().downcast::<&str>().unwrap(), - ); - - #[cfg(eyre_no_fmt_arguments_as_str)] - assert_eq!( - "oh no!", - bail_literal().unwrap_err().downcast::().unwrap(), - ); - - assert_eq!( - "oh no!", - bail_fmt().unwrap_err().downcast::().unwrap(), - ); - assert_eq!( - "oh no!", - bail_error() - .unwrap_err() - .downcast::() - .unwrap() - .to_string(), - ); -} - -#[test] -fn test_downcast_ref() { - maybe_install_handler().unwrap(); - - #[cfg(not(eyre_no_fmt_arguments_as_str))] - assert_eq!( - "oh no!", - *bail_literal().unwrap_err().downcast_ref::<&str>().unwrap(), - ); - - #[cfg(eyre_no_fmt_arguments_as_str)] - assert_eq!( - "oh no!", - *bail_literal() - .unwrap_err() - .downcast_ref::() - .unwrap(), - ); - - assert_eq!( - "oh no!", - bail_fmt().unwrap_err().downcast_ref::().unwrap(), - ); - assert_eq!( - "oh no!", - bail_error() - .unwrap_err() - .downcast_ref::() - .unwrap() - .to_string(), - ); -} - -#[test] -fn test_downcast_mut() { - maybe_install_handler().unwrap(); - - #[cfg(not(eyre_no_fmt_arguments_as_str))] - assert_eq!( - "oh no!", - *bail_literal().unwrap_err().downcast_mut::<&str>().unwrap(), - ); - - #[cfg(eyre_no_fmt_arguments_as_str)] - assert_eq!( - "oh no!", - *bail_literal() - .unwrap_err() - .downcast_mut::() - .unwrap(), - ); - - assert_eq!( - "oh no!", - bail_fmt().unwrap_err().downcast_mut::().unwrap(), - ); - assert_eq!( - "oh no!", - bail_error() - .unwrap_err() - .downcast_mut::() - .unwrap() - .to_string(), - ); -} - -#[test] -fn test_drop() { - maybe_install_handler().unwrap(); - - let has_dropped = Flag::new(); - let error: Report = Report::new(DetectDrop::new("DetectDrop", &has_dropped)); - drop(error.downcast::().unwrap()); - assert!(has_dropped.get()); -} - -#[test] -fn test_large_alignment() { - maybe_install_handler().unwrap(); - - #[repr(align(64))] - #[derive(Debug)] - struct LargeAlignedError(&'static str); - - impl Display for LargeAlignedError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.0) - } - } - - impl StdError for LargeAlignedError {} - - let error = Report::new(LargeAlignedError("oh no!")); - assert_eq!( - "oh no!", - error.downcast_ref::().unwrap().0 - ); -} - -#[test] -fn test_unsuccessful_downcast() { - maybe_install_handler().unwrap(); - - let mut error = bail_error().unwrap_err(); - assert!(error.downcast_ref::<&str>().is_none()); - assert!(error.downcast_mut::<&str>().is_none()); - assert!(error.downcast::<&str>().is_err()); -} diff --git a/third-party/vendor/eyre/tests/test_fmt.rs b/third-party/vendor/eyre/tests/test_fmt.rs deleted file mode 100644 index 292c93cc..00000000 --- a/third-party/vendor/eyre/tests/test_fmt.rs +++ /dev/null @@ -1,105 +0,0 @@ -mod common; - -use self::common::maybe_install_handler; -use eyre::{bail, Result, WrapErr}; -use std::io; - -fn f() -> Result<()> { - bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!")); -} - -fn g() -> Result<()> { - f().wrap_err("f failed") -} - -fn h() -> Result<()> { - g().wrap_err("g failed") -} - -const EXPECTED_ALTDISPLAY_F: &str = "oh no!"; - -const EXPECTED_ALTDISPLAY_G: &str = "f failed: oh no!"; - -const EXPECTED_ALTDISPLAY_H: &str = "g failed: f failed: oh no!"; - -const EXPECTED_DEBUG_F: &str = "oh no!"; - -const EXPECTED_DEBUG_G: &str = "\ -f failed - -Caused by: - oh no!\ -"; - -const EXPECTED_DEBUG_H: &str = "\ -g failed - -Caused by: - 0: f failed - 1: oh no!\ -"; - -const EXPECTED_ALTDEBUG_F: &str = "\ -Custom { - kind: PermissionDenied, - error: \"oh no!\", -}\ -"; - -const EXPECTED_ALTDEBUG_G: &str = "\ -Error { - msg: \"f failed\", - source: Custom { - kind: PermissionDenied, - error: \"oh no!\", - }, -}\ -"; - -const EXPECTED_ALTDEBUG_H: &str = "\ -Error { - msg: \"g failed\", - source: Error { - msg: \"f failed\", - source: Custom { - kind: PermissionDenied, - error: \"oh no!\", - }, - }, -}\ -"; - -#[test] -fn test_display() { - maybe_install_handler().unwrap(); - - assert_eq!("g failed", h().unwrap_err().to_string()); -} - -#[test] -fn test_altdisplay() { - maybe_install_handler().unwrap(); - - assert_eq!(EXPECTED_ALTDISPLAY_F, format!("{:#}", f().unwrap_err())); - assert_eq!(EXPECTED_ALTDISPLAY_G, format!("{:#}", g().unwrap_err())); - assert_eq!(EXPECTED_ALTDISPLAY_H, format!("{:#}", h().unwrap_err())); -} - -#[test] -#[cfg_attr(any(backtrace, track_caller), ignore)] -fn test_debug() { - maybe_install_handler().unwrap(); - - assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err())); - assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err())); - assert_eq!(EXPECTED_DEBUG_H, format!("{:?}", h().unwrap_err())); -} - -#[test] -fn test_altdebug() { - maybe_install_handler().unwrap(); - - assert_eq!(EXPECTED_ALTDEBUG_F, format!("{:#?}", f().unwrap_err())); - assert_eq!(EXPECTED_ALTDEBUG_G, format!("{:#?}", g().unwrap_err())); - assert_eq!(EXPECTED_ALTDEBUG_H, format!("{:#?}", h().unwrap_err())); -} diff --git a/third-party/vendor/eyre/tests/test_location.rs b/third-party/vendor/eyre/tests/test_location.rs deleted file mode 100644 index 766514a5..00000000 --- a/third-party/vendor/eyre/tests/test_location.rs +++ /dev/null @@ -1,183 +0,0 @@ -use std::panic::Location; - -use eyre::{OptionExt as _, WrapErr}; - -struct LocationHandler { - actual: Option<&'static str>, - expected: &'static str, -} - -impl LocationHandler { - fn new(expected: &'static str) -> Self { - LocationHandler { - actual: None, - expected, - } - } -} - -impl eyre::EyreHandler for LocationHandler { - fn debug( - &self, - _error: &(dyn std::error::Error + 'static), - _f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { - // we assume that if the compiler is new enough to support - // `track_caller` that we will always have `actual` be `Some`, so we can - // safely skip the assertion if the location is `None` which should only - // happen in older rust versions. - if let Some(actual) = self.actual { - assert_eq!(self.expected, actual); - } - - Ok(()) - } - - fn track_caller(&mut self, location: &'static Location<'static>) { - dbg!(location); - self.actual = Some(location.file()); - } -} - -#[test] -fn test_wrap_err() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - let err = read_path("totally_fake_path") - .wrap_err("oopsie") - .unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} - -#[cfg(not(miri))] -fn read_path(path: &str) -> Result { - std::fs::read_to_string(path) -} - -#[cfg(miri)] -fn read_path(_path: &str) -> Result { - // Miri doesn't support reading files, so we just return an error - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Miri doesn't support reading files", - )) -} - -#[test] -fn test_wrap_err_with() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - let err = read_path("totally_fake_path") - .wrap_err_with(|| "oopsie") - .unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} - -#[test] -fn test_option_ok_or_eyre() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - let err = None::<()>.ok_or_eyre("oopsie").unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} - -#[test] -fn test_context() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - let err = read_path("totally_fake_path") - .context("oopsie") - .unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} - -#[test] -fn test_with_context() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - let err = read_path("totally_fake_path") - .with_context(|| "oopsie") - .unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} - -#[test] -fn test_option_compat_wrap_err() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - use eyre::ContextCompat; - let err = None::<()>.wrap_err("oopsie").unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} - -#[test] -fn test_option_compat_wrap_err_with() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - use eyre::ContextCompat; - let err = None::<()>.wrap_err_with(|| "oopsie").unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} - -#[test] -fn test_option_compat_context() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - use eyre::ContextCompat; - let err = None::<()>.context("oopsie").unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} - -#[test] -fn test_option_compat_with_context() { - let _ = eyre::set_hook(Box::new(|_e| { - let expected_location = file!(); - Box::new(LocationHandler::new(expected_location)) - })); - - use eyre::ContextCompat; - let err = None::<()>.with_context(|| "oopsie").unwrap_err(); - - // should panic if the location isn't in our crate - println!("{:?}", err); -} diff --git a/third-party/vendor/eyre/tests/test_macros.rs b/third-party/vendor/eyre/tests/test_macros.rs deleted file mode 100644 index 41d3ddbb..00000000 --- a/third-party/vendor/eyre/tests/test_macros.rs +++ /dev/null @@ -1,102 +0,0 @@ -#![allow(clippy::eq_op)] -mod common; - -use self::common::*; -use eyre::{ensure, eyre, Result}; -use std::cell::Cell; -use std::future::Future; -use std::pin::Pin; -use std::task::Poll; - -#[test] -fn test_messages() { - maybe_install_handler().unwrap(); - - assert_eq!("oh no!", bail_literal().unwrap_err().to_string()); - assert_eq!("oh no!", bail_fmt().unwrap_err().to_string()); - assert_eq!("oh no!", bail_error().unwrap_err().to_string()); -} - -#[test] -fn test_ensure() { - maybe_install_handler().unwrap(); - - let f = || -> Result<()> { - ensure!(1 + 1 == 2, "This is correct"); - Ok(()) - }; - assert!(f().is_ok()); - - let v = 1; - let f = || -> Result<()> { - ensure!(v + v == 2, "This is correct, v: {}", v); - Ok(()) - }; - assert!(f().is_ok()); - - let f = || -> Result<()> { - ensure!(v + v == 1, "This is not correct, v: {}", v); - Ok(()) - }; - assert!(f().is_err()); - - let f = || { - ensure!(v + v == 1); - Ok(()) - }; - assert_eq!( - f().unwrap_err().to_string(), - "Condition failed: `v + v == 1`", - ); -} - -#[test] -fn test_temporaries() { - struct Ready(Option); - - impl Unpin for Ready {} - - impl Future for Ready { - type Output = T; - - fn poll(mut self: Pin<&mut Self>, _cx: &mut std::task::Context<'_>) -> Poll { - Poll::Ready(self.0.take().unwrap()) - } - } - - fn require_send_sync(_: impl Send + Sync) {} - - require_send_sync(async { - // If eyre hasn't dropped any temporary format_args it creates by the - // time it's done evaluating, those will stick around until the - // semicolon, which is on the other side of the await point, making the - // enclosing future non-Send. - let _ = Ready(Some(eyre!("..."))).await; - }); - - fn message(cell: Cell<&str>) -> &str { - cell.get() - } - - require_send_sync(async { - let _ = Ready(Some(eyre!(message(Cell::new("..."))))).await; - }); -} - -#[test] -#[cfg(not(eyre_no_fmt_args_capture))] -fn test_capture_format_args() { - maybe_install_handler().unwrap(); - - let var = 42; - let err = eyre!("interpolate {var}"); - assert_eq!("interpolate 42", err.to_string()); -} - -#[test] -fn test_brace_escape() { - maybe_install_handler().unwrap(); - - let err = eyre!("unterminated ${{..}} expression"); - assert_eq!("unterminated ${..} expression", err.to_string()); -} diff --git a/third-party/vendor/eyre/tests/test_no_install.rs b/third-party/vendor/eyre/tests/test_no_install.rs deleted file mode 100644 index 1279de7a..00000000 --- a/third-party/vendor/eyre/tests/test_no_install.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![cfg(not(feature = "auto-install"))] - -use eyre::{eyre, set_hook, DefaultHandler, Report}; - -#[test] -fn test_no_hook_panic() { - let panic_res = std::panic::catch_unwind(|| eyre!("this will never be displayed")); - assert!(panic_res.is_err()); - - let downcast_res = panic_res.unwrap_err().downcast::(); - assert_eq!( - *downcast_res.unwrap(), - "a handler must always be installed if the `auto-install` feature is disabled" - ); - - assert!(set_hook(Box::new(DefaultHandler::default_with)).is_ok()); - let _error: Report = eyre!("this will be displayed if returned"); -} diff --git a/third-party/vendor/eyre/tests/test_option.rs b/third-party/vendor/eyre/tests/test_option.rs deleted file mode 100644 index 7c9349ab..00000000 --- a/third-party/vendor/eyre/tests/test_option.rs +++ /dev/null @@ -1,15 +0,0 @@ -mod common; - -use self::common::maybe_install_handler; -use eyre::OptionExt; - -#[test] -fn test_option_ok_or_eyre() { - maybe_install_handler().unwrap(); - - let option: Option<()> = None; - - let result = option.ok_or_eyre("static str error"); - - assert_eq!(result.unwrap_err().to_string(), "static str error"); -} diff --git a/third-party/vendor/eyre/tests/test_pyo3.rs b/third-party/vendor/eyre/tests/test_pyo3.rs deleted file mode 100644 index e7f58c1b..00000000 --- a/third-party/vendor/eyre/tests/test_pyo3.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![cfg(feature = "pyo3")] - -use pyo3::prelude::*; - -use eyre::{bail, Result, WrapErr}; - -fn f() -> Result<()> { - use std::io; - bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!")); -} - -fn g() -> Result<()> { - f().wrap_err("f failed") -} - -fn h() -> Result<()> { - g().wrap_err("g failed") -} - -#[test] -fn test_pyo3_exception_contents() { - use pyo3::types::IntoPyDict; - - let err = h().unwrap_err(); - let expected_contents = format!("{:?}", err); - let pyerr = PyErr::from(err); - - Python::with_gil(|py| { - let locals = [("err", pyerr)].into_py_dict(py); - let pyerr = py.run("raise err", None, Some(locals)).unwrap_err(); - assert_eq!(pyerr.value(py).to_string(), expected_contents); - }) -} diff --git a/third-party/vendor/eyre/tests/test_repr.rs b/third-party/vendor/eyre/tests/test_repr.rs deleted file mode 100644 index 71a56637..00000000 --- a/third-party/vendor/eyre/tests/test_repr.rs +++ /dev/null @@ -1,36 +0,0 @@ -mod common; -mod drop; - -use self::common::maybe_install_handler; -use self::drop::{DetectDrop, Flag}; -use eyre::Report; -use std::marker::Unpin; -use std::mem; - -#[test] -fn test_error_size() { - assert_eq!(mem::size_of::(), mem::size_of::()); -} - -#[test] -fn test_null_pointer_optimization() { - assert_eq!( - mem::size_of::>(), - mem::size_of::() - ); -} - -#[test] -fn test_autotraits() { - fn assert() {} - assert::(); -} - -#[test] -fn test_drop() { - maybe_install_handler().unwrap(); - - let has_dropped = Flag::new(); - drop(Report::new(DetectDrop::new("TestDrop", &has_dropped))); - assert!(has_dropped.get()); -} diff --git a/third-party/vendor/eyre/tests/test_source.rs b/third-party/vendor/eyre/tests/test_source.rs deleted file mode 100644 index 709955c6..00000000 --- a/third-party/vendor/eyre/tests/test_source.rs +++ /dev/null @@ -1,75 +0,0 @@ -mod common; - -use self::common::maybe_install_handler; -use eyre::{eyre, Report}; -use std::error::Error as StdError; -use std::fmt::{self, Display}; -use std::io; - -#[derive(Debug)] -enum TestError { - Io(io::Error), -} - -impl Display for TestError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match self { - TestError::Io(e) => Display::fmt(e, formatter), - } - } -} - -impl StdError for TestError { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - match self { - TestError::Io(io) => Some(io), - } - } -} - -#[test] -fn test_literal_source() { - maybe_install_handler().unwrap(); - - let error: Report = eyre!("oh no!"); - assert!(error.source().is_none()); -} - -#[test] -fn test_variable_source() { - maybe_install_handler().unwrap(); - - let msg = "oh no!"; - let error = eyre!(msg); - assert!(error.source().is_none()); - - let msg = msg.to_owned(); - let error: Report = eyre!(msg); - assert!(error.source().is_none()); -} - -#[test] -fn test_fmt_source() { - maybe_install_handler().unwrap(); - - let error: Report = eyre!("{} {}!", "oh", "no"); - assert!(error.source().is_none()); -} - -#[test] -fn test_io_source() { - maybe_install_handler().unwrap(); - - let io = io::Error::new(io::ErrorKind::Other, "oh no!"); - let error: Report = eyre!(TestError::Io(io)); - assert_eq!("oh no!", error.source().unwrap().to_string()); -} - -#[test] -fn test_eyre_from_eyre() { - maybe_install_handler().unwrap(); - - let error: Report = eyre!("oh no!").wrap_err("context"); - let error = eyre!(error); - assert_eq!("oh no!", error.source().unwrap().to_string()); -} diff --git a/third-party/vendor/eyre/tests/test_toolchain.rs b/third-party/vendor/eyre/tests/test_toolchain.rs deleted file mode 100644 index 03093980..00000000 --- a/third-party/vendor/eyre/tests/test_toolchain.rs +++ /dev/null @@ -1,34 +0,0 @@ -// These tests check our build script against rustversion. - -#[rustversion::attr(not(nightly), ignore)] -#[test] -fn nightlytest() { - if !cfg!(nightly) { - panic!("nightly feature isn't set when the toolchain is nightly."); - } - if cfg!(any(beta, stable)) { - panic!("beta, stable, and nightly are mutually exclusive features.") - } -} - -#[rustversion::attr(not(beta), ignore)] -#[test] -fn betatest() { - if !cfg!(beta) { - panic!("beta feature is not set when the toolchain is beta."); - } - if cfg!(any(nightly, stable)) { - panic!("beta, stable, and nightly are mutually exclusive features.") - } -} - -#[rustversion::attr(not(stable), ignore)] -#[test] -fn stabletest() { - if !cfg!(stable) { - panic!("stable feature is not set when the toolchain is stable."); - } - if cfg!(any(nightly, beta)) { - panic!("beta, stable, and nightly are mutually exclusive features.") - } -} diff --git a/third-party/vendor/hashlink/.cargo-checksum.json b/third-party/vendor/hashlink/.cargo-checksum.json deleted file mode 100644 index 7628f9f9..00000000 --- a/third-party/vendor/hashlink/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"7ddf30caa64a1fe8784c1a515dfc8760ca15096c3f675dff705504246d1591f0","Cargo.toml":"818242810576677a1c0b01b7301177385ae27285b52769f91205289d6e2bc003","LICENSE-APACHE":"c144680885b29e4719e2a51f0aab5439a1e02d980692b5aaf086cae12727f28b","LICENSE-MIT":"e915669a595b11a200873df8286561881b0e04932f6412a585db6297ba0bc97c","README.md":"f2b040b9aa899d3bd9fbb6c2391054980b00e7f475b6066071c17dd59d614d1c","src/lib.rs":"1de536f36f50b780db29d9695970c28ce77677cf2de6a7e27bea148c905b719f","src/linked_hash_map.rs":"3ad55fbc903b37d2e351ef9f401d85abe4ef1aa87bf95989d1cd5fba8e5a0c2b","src/linked_hash_set.rs":"e67bdbcf0626b2f8b8520691882aa06f8662582b134f81be3f705f0b5434fb7a","src/lru_cache.rs":"9fc56c3cfb9575378f8e92cb48b031b1eaec9f6c3bb21886f7fb636d32645c8e","src/serde.rs":"5b216ccd4b21f3093bb4baf18b9f3943f9ae6f49d2faad2c3b566e8a0cb99851","tests/linked_hash_map.rs":"c2d259c9d0325f4b73268dc686b8cca8fc3c778c757012825a82474026f28634","tests/linked_hash_set.rs":"bfaa3018a99c5c36cf0059bf7836142c2cc69be7f03a8c20bd52131f877e2eec","tests/lru_cache.rs":"c0328001d53e2a0d1ef6fb36550e8cbb989ef1914cef3657f1832b280f4d4572","tests/serde.rs":"4e0b1c19c3c542f0b9adac72f6ff32907da6bb58b4f1810dcdf9cd4e2eef34b1"},"package":"e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"} \ No newline at end of file diff --git a/third-party/vendor/hashlink/CHANGELOG.md b/third-party/vendor/hashlink/CHANGELOG.md deleted file mode 100644 index ddfd27ab..00000000 --- a/third-party/vendor/hashlink/CHANGELOG.md +++ /dev/null @@ -1,81 +0,0 @@ -## [0.8.4] -- Now builds with `#![no_std]`. - -## [0.8.3] -- bump hashbrown to 0.14 - -## [0.8.2] -- bump hashbrown to 0.13 - -## [0.8.1] -- Add `retain_with_order` methods, equivalent to `retain` but which iterate - through the map in the proper linked list order - -## [0.8.0] -- API incompatible change: No longer re-export hashbrown types so that bumping - hashbrown is no longer an API compatible change. -- bump hashbrown to 0.12 -- Fix implementation of `shrink_to_fit` to not panic when called on non-empty - containers. - -## [0.7.0] -- API incompatible change: depend on hashbrown 0.11, changes re-exported types. -- Fix `LinkedHashSet::back` to take `&self` not `&mut self`. -- API incompatible change: equality tests on `LinkedHashSet` are now *ordered*, - similar to `LinkedHashMap`. -- Make the serde `Deserialize` implementations on `LinkedHashMap` and - `LinkedHashSet` generic on the `BuildHasher` type. -- Add `to_back` and `to_front` methods for `LinkedHashMap` to control entry - order. - -## [0.6.0] -- API incompatible change: depend on hashbrown 0.9, re-export renamed - hashbrown::TryReserveError type. -- Add a `Debug` impl to `LruCache` (thanks @thomcc!) -- Adjust trait bounds for `LinkedHashMap::retain`, `LinkedHashSet::default` to - be less strict (to match hashbrown) -- Adjust trait bounds for all `Debug` impls to be less strict (to match - hashbrown). -- Adjust trait bounds for all `IntoIterator` impls to be less strict (to match - hashbrown). -- Adjust trait bounds for `LruCache::with_hasher`, `LruCache::capacity`, - `LruCache::len`, `LruCache::is_empty`, `LruCache::clear`, `LruCache::iter`, - `LruCache::iter_mut`, and `LruCache::drain` to be less strict -- Add optional serde support for `LinkedHashMap` and `LinkedHashSet`. -- Add `to_back` and `to_front` methods for LinkedHashSet to control entry order. - -## [0.5.1] -- Add `LinkedHashMap::remove_entry` and `LruCache::remove_entry` -- Add `LruCache::new_unbounded` constructor that sets capacity to usize::MAX -- Add `LruCache::get` method to go with `LruCache::get_mut` -- Add `LruCache::peek` and `LruCache::peek_mut` to access the cache without - moving the entry in the LRU list - -## [0.5.0] -- API incompatible change: depend on hashbrown 0.7 - -## [0.4.0] -- API incompatible change: depend on hashbrown 0.6 -- Passes miri - -## [0.3.0] -- Add some *minimal* documentation for methods that change the internal ordering. -- Decide on a pattern for methods that change the internal ordering: the word - "insert" means that it will move an existing entry to the back. -- Some methods have been renamed to conform to the above system. - -## [0.2.1] -- Fix variance for LinkedHashMap (now covariant where appropriate) -- Add Debug impls to many more associated types -- Add LinkedHashSet -- Add `LinkedHashMap::retain` - -## [0.2.0] -- Move `linked_hash_map` into its own module -- Add `LruCache` type ported from `lru-cache` crate into its own module -- Add `LruCache` entry and raw-entry API -- Add `linked_hash_map` `IntoIter` iterator that is different from `Drain` iterator -- Make `Drain` iterator recycle freed linked list nodes - -## [0.1.0] -- Initial release diff --git a/third-party/vendor/hashlink/Cargo.toml b/third-party/vendor/hashlink/Cargo.toml deleted file mode 100644 index e990fd66..00000000 --- a/third-party/vendor/hashlink/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -name = "hashlink" -version = "0.8.4" -authors = ["kyren "] -description = "HashMap-like containers that hold their key-value pairs in a user controllable order" -documentation = "https://docs.rs/hashlink" -readme = "README.md" -keywords = [ - "data-structures", - "no_std", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/kyren/hashlink" - -[dependencies.hashbrown] -version = "0.14" - -[dependencies.serde] -version = "1.0" -optional = true -default-features = false - -[dev-dependencies.rustc-hash] -version = "1.1" - -[dev-dependencies.serde_test] -version = "1.0" - -[features] -serde_impl = ["serde"] - -[badges.circle-ci] -branch = "master" -repository = "kyren/hashlink" diff --git a/third-party/vendor/hashlink/LICENSE-APACHE b/third-party/vendor/hashlink/LICENSE-APACHE deleted file mode 100644 index 1b22bef9..00000000 --- a/third-party/vendor/hashlink/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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. \ No newline at end of file diff --git a/third-party/vendor/hashlink/LICENSE-MIT b/third-party/vendor/hashlink/LICENSE-MIT deleted file mode 100644 index b3cad876..00000000 --- a/third-party/vendor/hashlink/LICENSE-MIT +++ /dev/null @@ -1,26 +0,0 @@ -This work is derived in part from the `linked-hash-map` crate, Copyright (c) -2015 The Rust Project Developers - -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. \ No newline at end of file diff --git a/third-party/vendor/hashlink/README.md b/third-party/vendor/hashlink/README.md deleted file mode 100644 index 9272b0d4..00000000 --- a/third-party/vendor/hashlink/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# hashlink -- HashMap-like containers that hold their key-value pairs in a user controllable order - -[![Build Status](https://img.shields.io/circleci/project/github/kyren/hashlink.svg)](https://circleci.com/gh/kyren/hashlink) -[![Latest Version](https://img.shields.io/crates/v/hashlink.svg)](https://crates.io/crates/hashlink) -[![API Documentation](https://docs.rs/hashlink/badge.svg)](https://docs.rs/hashlink) - -This crate is a fork of -[linked-hash-map](https://github.com/contain-rs/linked-hash-map) that builds on -top of [hashbrown](https://github.com/rust-lang/hashbrown) to implement more up -to date versions of `LinkedHashMap` `LinkedHashSet`, and `LruCache`. - -One important API change is that when a `LinkedHashMap` is used as a LRU cache, -it allows you to easily retrieve an entry and move it to the back OR produce a -new entry at the back without needlessly repeating key hashing and lookups: - -``` rust -let mut lru_cache = LinkedHashMap::new(); -let key = "key".to_owned(); -// Try to find my expensive to construct and hash key -let _cached_val = match lru_cache.raw_entry_mut().from_key(&key) { - RawEntryMut::Occupied(mut occupied) => { - // Cache hit, move entry to the back. - occupied.to_back(); - occupied.into_mut() - } - RawEntryMut::Vacant(vacant) => { - // Insert expensive to construct key and expensive to compute value, - // automatically inserted at the back. - vacant.insert(key.clone(), 42).1 - } -}; -``` - -Or, a simpler way to do the same thing: - -``` rust -let mut lru_cache = LinkedHashMap::new(); -let key = "key".to_owned(); -let _cached_val = lru_cache - .raw_entry_mut() - .from_key(&key) - .or_insert_with(|| (key.clone(), 42)); -``` - -This crate contains a decent amount of unsafe code from handling its internal -linked list, and the unsafe code has diverged quite a lot from the original -`linked-hash-map` implementation. It currently passes tests under miri and -sanitizers, but it should probably still receive more review and testing, and -check for test code coverage. - -## Credit - -There is a huge amount of code in this crate that is copied verbatim from -`linked-hash-map` and `hashbrown`, especially tests, associated types like -iterators, and things like `Debug` impls. - -## License - -This library is licensed the same as -[linked-hash-map](https://github.com/contain-rs/linked-hash-map) and -[hashbrown](https://github.com/rust-lang/hashbrown), it is licensed under either -of: - -* MIT license [LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT -* Apache License 2.0 [LICENSE-APACHE](LICENSE-APACHE) or https://opensource.org/licenses/Apache-2.0 - -at your option. diff --git a/third-party/vendor/hashlink/src/lib.rs b/third-party/vendor/hashlink/src/lib.rs deleted file mode 100644 index 4d80905d..00000000 --- a/third-party/vendor/hashlink/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![no_std] -extern crate alloc; - -pub mod linked_hash_map; -pub mod linked_hash_set; -pub mod lru_cache; -#[cfg(feature = "serde_impl")] -pub mod serde; - -pub use linked_hash_map::LinkedHashMap; -pub use linked_hash_set::LinkedHashSet; -pub use lru_cache::LruCache; diff --git a/third-party/vendor/hashlink/src/linked_hash_map.rs b/third-party/vendor/hashlink/src/linked_hash_map.rs deleted file mode 100644 index f9a3c812..00000000 --- a/third-party/vendor/hashlink/src/linked_hash_map.rs +++ /dev/null @@ -1,2180 +0,0 @@ -use core::{ - alloc::Layout, - borrow::Borrow, - cmp::Ordering, - fmt, - hash::{BuildHasher, Hash, Hasher}, - iter::FromIterator, - marker::PhantomData, - mem::{self, MaybeUninit}, - ops::{Index, IndexMut}, - ptr::{self, NonNull}, -}; - -use alloc::boxed::Box; -use hashbrown::{hash_map, HashMap}; - -pub enum TryReserveError { - CapacityOverflow, - AllocError { layout: Layout }, -} - -/// A version of `HashMap` that has a user controllable order for its entries. -/// -/// It achieves this by keeping its entries in an internal linked list and using a `HashMap` to -/// point at nodes in this linked list. -/// -/// The order of entries defaults to "insertion order", but the user can also modify the order of -/// existing entries by manually moving them to the front or back. -/// -/// There are two kinds of methods that modify the order of the internal list: -/// -/// * Methods that have names like `to_front` and `to_back` will unsurprisingly move an existing -/// entry to the front or back -/// * Methods that have the word `insert` will insert a new entry ot the back of the list, and if -/// that method might replace an entry, that method will *also move that existing entry to the -/// back*. -pub struct LinkedHashMap { - map: HashMap>, (), NullHasher>, - // We need to keep any custom hash builder outside of the HashMap so we can access it alongside - // the entry API without mutable aliasing. - hash_builder: S, - // Circular linked list of nodes. If `values` is non-null, it will point to a "guard node" - // which will never have an initialized key or value, `values.prev` will contain the last key / - // value in the list, `values.next` will contain the first key / value in the list. - values: Option>>, - // *Singly* linked list of free nodes. The `prev` pointers in the free list should be assumed - // invalid. - free: Option>>, -} - -impl LinkedHashMap { - #[inline] - pub fn new() -> Self { - Self { - hash_builder: hash_map::DefaultHashBuilder::default(), - map: HashMap::with_hasher(NullHasher), - values: None, - free: None, - } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Self { - Self { - hash_builder: hash_map::DefaultHashBuilder::default(), - map: HashMap::with_capacity_and_hasher(capacity, NullHasher), - values: None, - free: None, - } - } -} - -impl LinkedHashMap { - #[inline] - pub fn with_hasher(hash_builder: S) -> Self { - Self { - hash_builder, - map: HashMap::with_hasher(NullHasher), - values: None, - free: None, - } - } - - #[inline] - pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { - Self { - hash_builder, - map: HashMap::with_capacity_and_hasher(capacity, NullHasher), - values: None, - free: None, - } - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.map.reserve(additional); - } - - #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.map.try_reserve(additional).map_err(|e| match e { - hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow, - hashbrown::TryReserveError::AllocError { layout } => { - TryReserveError::AllocError { layout } - } - }) - } - - #[inline] - pub fn len(&self) -> usize { - self.map.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - #[inline] - pub fn clear(&mut self) { - self.map.clear(); - if let Some(mut values) = self.values { - unsafe { - drop_value_nodes(values); - values.as_mut().links.value = ValueLinks { - prev: values, - next: values, - }; - } - } - } - - #[inline] - pub fn iter(&self) -> Iter { - let (head, tail) = if let Some(values) = self.values { - unsafe { - let ValueLinks { next, prev } = values.as_ref().links.value; - (next.as_ptr(), prev.as_ptr()) - } - } else { - (ptr::null_mut(), ptr::null_mut()) - }; - - Iter { - head, - tail, - remaining: self.len(), - marker: PhantomData, - } - } - - #[inline] - pub fn iter_mut(&mut self) -> IterMut { - let (head, tail) = if let Some(values) = self.values { - unsafe { - let ValueLinks { next, prev } = values.as_ref().links.value; - (Some(next), Some(prev)) - } - } else { - (None, None) - }; - - IterMut { - head, - tail, - remaining: self.len(), - marker: PhantomData, - } - } - - #[inline] - pub fn drain(&mut self) -> Drain<'_, K, V> { - unsafe { - let (head, tail) = if let Some(mut values) = self.values { - let ValueLinks { next, prev } = values.as_ref().links.value; - values.as_mut().links.value = ValueLinks { - next: values, - prev: values, - }; - (Some(next), Some(prev)) - } else { - (None, None) - }; - let len = self.len(); - - self.map.clear(); - - Drain { - free: (&mut self.free).into(), - head, - tail, - remaining: len, - marker: PhantomData, - } - } - } - - #[inline] - pub fn keys(&self) -> Keys { - Keys { inner: self.iter() } - } - - #[inline] - pub fn values(&self) -> Values { - Values { inner: self.iter() } - } - - #[inline] - pub fn values_mut(&mut self) -> ValuesMut { - ValuesMut { - inner: self.iter_mut(), - } - } - - #[inline] - pub fn front(&self) -> Option<(&K, &V)> { - if self.is_empty() { - return None; - } - unsafe { - let front = (*self.values.as_ptr()).links.value.next.as_ptr(); - let (key, value) = (*front).entry_ref(); - Some((key, value)) - } - } - - #[inline] - pub fn back(&self) -> Option<(&K, &V)> { - if self.is_empty() { - return None; - } - unsafe { - let back = &*(*self.values.as_ptr()).links.value.prev.as_ptr(); - let (key, value) = (*back).entry_ref(); - Some((key, value)) - } - } - - #[inline] - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&K, &mut V) -> bool, - { - let free = self.free; - let mut drop_filtered_values = DropFilteredValues { - free: &mut self.free, - cur_free: free, - }; - - self.map.retain(|&node, _| unsafe { - let (k, v) = (*node.as_ptr()).entry_mut(); - if f(k, v) { - true - } else { - drop_filtered_values.drop_later(node); - false - } - }); - } - - #[inline] - pub fn hasher(&self) -> &S { - &self.hash_builder - } - - #[inline] - pub fn capacity(&self) -> usize { - self.map.capacity() - } -} - -impl LinkedHashMap -where - K: Eq + Hash, - S: BuildHasher, -{ - #[inline] - pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S> { - match self.raw_entry_mut().from_key(&key) { - RawEntryMut::Occupied(occupied) => Entry::Occupied(OccupiedEntry { - key, - raw_entry: occupied, - }), - RawEntryMut::Vacant(vacant) => Entry::Vacant(VacantEntry { - key, - raw_entry: vacant, - }), - } - } - - #[inline] - pub fn get(&self, k: &Q) -> Option<&V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.raw_entry().from_key(k).map(|(_, v)| v) - } - - #[inline] - pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.raw_entry().from_key(k) - } - - #[inline] - pub fn contains_key(&self, k: &Q) -> bool - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.get(k).is_some() - } - - #[inline] - pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - match self.raw_entry_mut().from_key(k) { - RawEntryMut::Occupied(occupied) => Some(occupied.into_mut()), - RawEntryMut::Vacant(_) => None, - } - } - - /// Inserts the given key / value pair at the *back* of the internal linked list. - /// - /// Returns the previously set value, if one existed prior to this call. After this call, - /// calling `LinkedHashMap::back` will return a reference to this key / value pair. - #[inline] - pub fn insert(&mut self, k: K, v: V) -> Option { - match self.raw_entry_mut().from_key(&k) { - RawEntryMut::Occupied(mut occupied) => { - occupied.to_back(); - Some(occupied.replace_value(v)) - } - RawEntryMut::Vacant(vacant) => { - vacant.insert(k, v); - None - } - } - } - - /// If the given key is not in this map, inserts the key / value pair at the *back* of the - /// internal linked list and returns `None`, otherwise, replaces the existing value with the - /// given value *without* moving the entry in the internal linked list and returns the previous - /// value. - #[inline] - pub fn replace(&mut self, k: K, v: V) -> Option { - match self.raw_entry_mut().from_key(&k) { - RawEntryMut::Occupied(mut occupied) => Some(occupied.replace_value(v)), - RawEntryMut::Vacant(vacant) => { - vacant.insert(k, v); - None - } - } - } - - #[inline] - pub fn remove(&mut self, k: &Q) -> Option - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - match self.raw_entry_mut().from_key(&k) { - RawEntryMut::Occupied(occupied) => Some(occupied.remove()), - RawEntryMut::Vacant(_) => None, - } - } - - #[inline] - pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - match self.raw_entry_mut().from_key(&k) { - RawEntryMut::Occupied(occupied) => Some(occupied.remove_entry()), - RawEntryMut::Vacant(_) => None, - } - } - - #[inline] - pub fn pop_front(&mut self) -> Option<(K, V)> { - if self.is_empty() { - return None; - } - unsafe { - let front = (*self.values.as_ptr()).links.value.next; - match self.map.raw_entry_mut().from_hash( - hash_key(&self.hash_builder, front.as_ref().key_ref()), - |k| (*k).as_ref().key_ref().eq(front.as_ref().key_ref()), - ) { - hash_map::RawEntryMut::Occupied(occupied) => { - Some(remove_node(&mut self.free, occupied.remove_entry().0)) - } - hash_map::RawEntryMut::Vacant(_) => None, - } - } - } - - #[inline] - pub fn pop_back(&mut self) -> Option<(K, V)> { - if self.is_empty() { - return None; - } - unsafe { - let back = (*self.values.as_ptr()).links.value.prev; - match self - .map - .raw_entry_mut() - .from_hash(hash_key(&self.hash_builder, back.as_ref().key_ref()), |k| { - (*k).as_ref().key_ref().eq(back.as_ref().key_ref()) - }) { - hash_map::RawEntryMut::Occupied(occupied) => { - Some(remove_node(&mut self.free, occupied.remove_entry().0)) - } - hash_map::RawEntryMut::Vacant(_) => None, - } - } - } - - /// If an entry with this key exists, move it to the front of the list and return a reference to - /// the value. - #[inline] - pub fn to_front(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - match self.raw_entry_mut().from_key(k) { - RawEntryMut::Occupied(mut occupied) => { - occupied.to_front(); - Some(occupied.into_mut()) - } - RawEntryMut::Vacant(_) => None, - } - } - - /// If an entry with this key exists, move it to the back of the list and return a reference to - /// the value. - #[inline] - pub fn to_back(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - match self.raw_entry_mut().from_key(k) { - RawEntryMut::Occupied(mut occupied) => { - occupied.to_back(); - Some(occupied.into_mut()) - } - RawEntryMut::Vacant(_) => None, - } - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - unsafe { - let len = self.map.len(); - if len != self.map.capacity() { - self.map = HashMap::with_hasher(NullHasher); - self.map.reserve(len); - - if let Some(guard) = self.values { - let mut cur = guard.as_ref().links.value.next; - while cur != guard { - let hash = hash_key(&self.hash_builder, cur.as_ref().key_ref()); - match self - .map - .raw_entry_mut() - .from_hash(hash, |k| (*k).as_ref().key_ref().eq(cur.as_ref().key_ref())) - { - hash_map::RawEntryMut::Occupied(_) => unreachable!(), - hash_map::RawEntryMut::Vacant(vacant) => { - let hash_builder = &self.hash_builder; - vacant.insert_with_hasher(hash, cur, (), |k| { - hash_key(hash_builder, (*k).as_ref().key_ref()) - }); - } - } - cur = cur.as_ref().links.value.next; - } - } - } - - drop_free_nodes(self.free); - self.free = None; - } - } - - pub fn retain_with_order(&mut self, mut f: F) - where - F: FnMut(&K, &mut V) -> bool, - { - let free = self.free; - let mut drop_filtered_values = DropFilteredValues { - free: &mut self.free, - cur_free: free, - }; - - if let Some(values) = self.values { - unsafe { - let mut cur = values.as_ref().links.value.next; - while cur != values { - let next = cur.as_ref().links.value.next; - let filter = { - let (k, v) = (*cur.as_ptr()).entry_mut(); - !f(k, v) - }; - if filter { - let k = (*cur.as_ptr()).key_ref(); - let hash = hash_key(&self.hash_builder, k); - match self - .map - .raw_entry_mut() - .from_hash(hash, |o| (*o).as_ref().key_ref().eq(k)) - { - hash_map::RawEntryMut::Occupied(entry) => { - entry.remove(); - drop_filtered_values.drop_later(cur); - } - hash_map::RawEntryMut::Vacant(_) => unreachable!(), - } - } - cur = next; - } - } - } - } -} - -impl LinkedHashMap -where - S: BuildHasher, -{ - #[inline] - pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> { - RawEntryBuilder { - hash_builder: &self.hash_builder, - entry: self.map.raw_entry(), - } - } - - #[inline] - pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S> { - RawEntryBuilderMut { - hash_builder: &self.hash_builder, - values: &mut self.values, - free: &mut self.free, - entry: self.map.raw_entry_mut(), - } - } -} - -impl Default for LinkedHashMap -where - S: Default, -{ - #[inline] - fn default() -> Self { - Self::with_hasher(S::default()) - } -} - -impl FromIterator<(K, V)> for LinkedHashMap { - #[inline] - fn from_iter>(iter: I) -> Self { - let iter = iter.into_iter(); - let mut map = Self::with_capacity_and_hasher(iter.size_hint().0, S::default()); - map.extend(iter); - map - } -} - -impl fmt::Debug for LinkedHashMap -where - K: fmt::Debug, - V: fmt::Debug, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_map().entries(self).finish() - } -} - -impl PartialEq for LinkedHashMap { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.len() == other.len() && self.iter().eq(other) - } -} - -impl Eq for LinkedHashMap {} - -impl PartialOrd - for LinkedHashMap -{ - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.iter().partial_cmp(other) - } - - #[inline] - fn lt(&self, other: &Self) -> bool { - self.iter().lt(other) - } - - #[inline] - fn le(&self, other: &Self) -> bool { - self.iter().le(other) - } - - #[inline] - fn ge(&self, other: &Self) -> bool { - self.iter().ge(other) - } - - #[inline] - fn gt(&self, other: &Self) -> bool { - self.iter().gt(other) - } -} - -impl Ord for LinkedHashMap { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - self.iter().cmp(other) - } -} - -impl Hash for LinkedHashMap { - #[inline] - fn hash(&self, h: &mut H) { - for e in self.iter() { - e.hash(h); - } - } -} - -impl Drop for LinkedHashMap { - #[inline] - fn drop(&mut self) { - unsafe { - if let Some(values) = self.values { - drop_value_nodes(values); - let _ = Box::from_raw(values.as_ptr()); - } - drop_free_nodes(self.free); - } - } -} - -unsafe impl Send for LinkedHashMap {} -unsafe impl Sync for LinkedHashMap {} - -impl<'a, K, V, S, Q> Index<&'a Q> for LinkedHashMap -where - K: Hash + Eq + Borrow, - S: BuildHasher, - Q: Eq + Hash + ?Sized, -{ - type Output = V; - - #[inline] - fn index(&self, index: &'a Q) -> &V { - self.get(index).expect("no entry found for key") - } -} - -impl<'a, K, V, S, Q> IndexMut<&'a Q> for LinkedHashMap -where - K: Hash + Eq + Borrow, - S: BuildHasher, - Q: Eq + Hash + ?Sized, -{ - #[inline] - fn index_mut(&mut self, index: &'a Q) -> &mut V { - self.get_mut(index).expect("no entry found for key") - } -} - -impl Clone for LinkedHashMap { - #[inline] - fn clone(&self) -> Self { - let mut map = Self::with_hasher(self.hash_builder.clone()); - map.extend(self.iter().map(|(k, v)| (k.clone(), v.clone()))); - map - } -} - -impl Extend<(K, V)> for LinkedHashMap { - #[inline] - fn extend>(&mut self, iter: I) { - for (k, v) in iter { - self.insert(k, v); - } - } -} - -impl<'a, K, V, S> Extend<(&'a K, &'a V)> for LinkedHashMap -where - K: 'a + Hash + Eq + Copy, - V: 'a + Copy, - S: BuildHasher, -{ - #[inline] - fn extend>(&mut self, iter: I) { - for (&k, &v) in iter { - self.insert(k, v); - } - } -} - -pub enum Entry<'a, K, V, S> { - Occupied(OccupiedEntry<'a, K, V>), - Vacant(VacantEntry<'a, K, V, S>), -} - -impl fmt::Debug for Entry<'_, K, V, S> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), - Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), - } - } -} - -impl<'a, K, V, S> Entry<'a, K, V, S> { - /// If this entry is vacant, inserts a new entry with the given value and returns a reference to - /// it. - /// - /// If this entry is occupied, this method *moves the occupied entry to the back of the internal - /// linked list* and returns a reference to the existing value. - #[inline] - pub fn or_insert(self, default: V) -> &'a mut V - where - K: Hash, - S: BuildHasher, - { - match self { - Entry::Occupied(mut entry) => { - entry.to_back(); - entry.into_mut() - } - Entry::Vacant(entry) => entry.insert(default), - } - } - - /// Similar to `Entry::or_insert`, but accepts a function to construct a new value if this entry - /// is vacant. - #[inline] - pub fn or_insert_with V>(self, default: F) -> &'a mut V - where - K: Hash, - S: BuildHasher, - { - match self { - Entry::Occupied(mut entry) => { - entry.to_back(); - entry.into_mut() - } - Entry::Vacant(entry) => entry.insert(default()), - } - } - - #[inline] - pub fn key(&self) -> &K { - match *self { - Entry::Occupied(ref entry) => entry.key(), - Entry::Vacant(ref entry) => entry.key(), - } - } - - #[inline] - pub fn and_modify(self, f: F) -> Self - where - F: FnOnce(&mut V), - { - match self { - Entry::Occupied(mut entry) => { - f(entry.get_mut()); - Entry::Occupied(entry) - } - Entry::Vacant(entry) => Entry::Vacant(entry), - } - } -} - -pub struct OccupiedEntry<'a, K, V> { - key: K, - raw_entry: RawOccupiedEntryMut<'a, K, V>, -} - -impl fmt::Debug for OccupiedEntry<'_, K, V> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OccupiedEntry") - .field("key", self.key()) - .field("value", self.get()) - .finish() - } -} - -impl<'a, K, V> OccupiedEntry<'a, K, V> { - #[inline] - pub fn key(&self) -> &K { - self.raw_entry.key() - } - - #[inline] - pub fn remove_entry(self) -> (K, V) { - self.raw_entry.remove_entry() - } - - #[inline] - pub fn get(&self) -> &V { - self.raw_entry.get() - } - - #[inline] - pub fn get_mut(&mut self) -> &mut V { - self.raw_entry.get_mut() - } - - #[inline] - pub fn into_mut(self) -> &'a mut V { - self.raw_entry.into_mut() - } - - #[inline] - pub fn to_back(&mut self) { - self.raw_entry.to_back() - } - - #[inline] - pub fn to_front(&mut self) { - self.raw_entry.to_front() - } - - /// Replaces this entry's value with the provided value. - /// - /// Similarly to `LinkedHashMap::insert`, this moves the existing entry to the back of the - /// internal linked list. - #[inline] - pub fn insert(&mut self, value: V) -> V { - self.raw_entry.to_back(); - self.raw_entry.replace_value(value) - } - - #[inline] - pub fn remove(self) -> V { - self.raw_entry.remove() - } - - /// Similar to `OccupiedEntry::replace_entry`, but *does* move the entry to the back of the - /// internal linked list. - #[inline] - pub fn insert_entry(mut self, value: V) -> (K, V) { - self.raw_entry.to_back(); - self.replace_entry(value) - } - - /// Replaces the entry's key with the key provided to `LinkedHashMap::entry`, and replaces the - /// entry's value with the given `value` parameter. - /// - /// Does *not* move the entry to the back of the internal linked list. - pub fn replace_entry(mut self, value: V) -> (K, V) { - let old_key = mem::replace(self.raw_entry.key_mut(), self.key); - let old_value = mem::replace(self.raw_entry.get_mut(), value); - (old_key, old_value) - } - - /// Replaces this entry's key with the key provided to `LinkedHashMap::entry`. - /// - /// Does *not* move the entry to the back of the internal linked list. - #[inline] - pub fn replace_key(mut self) -> K { - mem::replace(self.raw_entry.key_mut(), self.key) - } -} - -pub struct VacantEntry<'a, K, V, S> { - key: K, - raw_entry: RawVacantEntryMut<'a, K, V, S>, -} - -impl fmt::Debug for VacantEntry<'_, K, V, S> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("VacantEntry").field(self.key()).finish() - } -} - -impl<'a, K, V, S> VacantEntry<'a, K, V, S> { - #[inline] - pub fn key(&self) -> &K { - &self.key - } - - #[inline] - pub fn into_key(self) -> K { - self.key - } - - /// Insert's the key for this vacant entry paired with the given value as a new entry at the - /// *back* of the internal linked list. - #[inline] - pub fn insert(self, value: V) -> &'a mut V - where - K: Hash, - S: BuildHasher, - { - self.raw_entry.insert(self.key, value).1 - } -} - -pub struct RawEntryBuilder<'a, K, V, S> { - hash_builder: &'a S, - entry: hash_map::RawEntryBuilder<'a, NonNull>, (), NullHasher>, -} - -impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> -where - S: BuildHasher, -{ - #[inline] - pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - let hash = hash_key(self.hash_builder, k); - self.from_key_hashed_nocheck(hash, k) - } - - #[inline] - pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.from_hash(hash, move |o| k.eq(o.borrow())) - } - - #[inline] - pub fn from_hash( - self, - hash: u64, - mut is_match: impl FnMut(&K) -> bool, - ) -> Option<(&'a K, &'a V)> { - unsafe { - let node = *self - .entry - .from_hash(hash, move |k| is_match((*k).as_ref().key_ref()))? - .0; - - let (key, value) = (*node.as_ptr()).entry_ref(); - Some((key, value)) - } - } -} - -unsafe impl<'a, K, V, S> Send for RawEntryBuilder<'a, K, V, S> -where - K: Send, - V: Send, - S: Send, -{ -} - -unsafe impl<'a, K, V, S> Sync for RawEntryBuilder<'a, K, V, S> -where - K: Sync, - V: Sync, - S: Sync, -{ -} - -pub struct RawEntryBuilderMut<'a, K, V, S> { - hash_builder: &'a S, - values: &'a mut Option>>, - free: &'a mut Option>>, - entry: hash_map::RawEntryBuilderMut<'a, NonNull>, (), NullHasher>, -} - -impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> -where - S: BuildHasher, -{ - #[inline] - pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - let hash = hash_key(self.hash_builder, k); - self.from_key_hashed_nocheck(hash, k) - } - - #[inline] - pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.from_hash(hash, move |o| k.eq(o.borrow())) - } - - #[inline] - pub fn from_hash( - self, - hash: u64, - mut is_match: impl FnMut(&K) -> bool, - ) -> RawEntryMut<'a, K, V, S> { - let entry = self - .entry - .from_hash(hash, move |k| is_match(unsafe { (*k).as_ref().key_ref() })); - - match entry { - hash_map::RawEntryMut::Occupied(occupied) => { - RawEntryMut::Occupied(RawOccupiedEntryMut { - free: self.free, - values: self.values, - entry: occupied, - }) - } - hash_map::RawEntryMut::Vacant(vacant) => RawEntryMut::Vacant(RawVacantEntryMut { - hash_builder: self.hash_builder, - values: self.values, - free: self.free, - entry: vacant, - }), - } - } -} - -unsafe impl<'a, K, V, S> Send for RawEntryBuilderMut<'a, K, V, S> -where - K: Send, - V: Send, - S: Send, -{ -} - -unsafe impl<'a, K, V, S> Sync for RawEntryBuilderMut<'a, K, V, S> -where - K: Sync, - V: Sync, - S: Sync, -{ -} - -pub enum RawEntryMut<'a, K, V, S> { - Occupied(RawOccupiedEntryMut<'a, K, V>), - Vacant(RawVacantEntryMut<'a, K, V, S>), -} - -impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { - /// Similarly to `Entry::or_insert`, if this entry is occupied, it will move the existing entry - /// to the back of the internal linked list. - #[inline] - pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) - where - K: Hash, - S: BuildHasher, - { - match self { - RawEntryMut::Occupied(mut entry) => { - entry.to_back(); - entry.into_key_value() - } - RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val), - } - } - - /// Similarly to `Entry::or_insert_with`, if this entry is occupied, it will move the existing - /// entry to the back of the internal linked list. - #[inline] - pub fn or_insert_with(self, default: F) -> (&'a mut K, &'a mut V) - where - F: FnOnce() -> (K, V), - K: Hash, - S: BuildHasher, - { - match self { - RawEntryMut::Occupied(mut entry) => { - entry.to_back(); - entry.into_key_value() - } - RawEntryMut::Vacant(entry) => { - let (k, v) = default(); - entry.insert(k, v) - } - } - } - - #[inline] - pub fn and_modify(self, f: F) -> Self - where - F: FnOnce(&mut K, &mut V), - { - match self { - RawEntryMut::Occupied(mut entry) => { - { - let (k, v) = entry.get_key_value_mut(); - f(k, v); - } - RawEntryMut::Occupied(entry) - } - RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), - } - } -} - -pub struct RawOccupiedEntryMut<'a, K, V> { - free: &'a mut Option>>, - values: &'a mut Option>>, - entry: hash_map::RawOccupiedEntryMut<'a, NonNull>, (), NullHasher>, -} - -impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { - #[inline] - pub fn key(&self) -> &K { - self.get_key_value().0 - } - - #[inline] - pub fn key_mut(&mut self) -> &mut K { - self.get_key_value_mut().0 - } - - #[inline] - pub fn into_key(self) -> &'a mut K { - self.into_key_value().0 - } - - #[inline] - pub fn get(&self) -> &V { - self.get_key_value().1 - } - - #[inline] - pub fn get_mut(&mut self) -> &mut V { - self.get_key_value_mut().1 - } - - #[inline] - pub fn into_mut(self) -> &'a mut V { - self.into_key_value().1 - } - - #[inline] - pub fn get_key_value(&self) -> (&K, &V) { - unsafe { - let node = *self.entry.key(); - let (key, value) = (*node.as_ptr()).entry_ref(); - (key, value) - } - } - - #[inline] - pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { - unsafe { - let node = *self.entry.key_mut(); - let (key, value) = (*node.as_ptr()).entry_mut(); - (key, value) - } - } - - #[inline] - pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { - unsafe { - let node = *self.entry.into_key(); - let (key, value) = (*node.as_ptr()).entry_mut(); - (key, value) - } - } - - #[inline] - pub fn to_back(&mut self) { - unsafe { - let node = *self.entry.key_mut(); - detach_node(node); - attach_before(node, NonNull::new_unchecked(self.values.as_ptr())); - } - } - - #[inline] - pub fn to_front(&mut self) { - unsafe { - let node = *self.entry.key_mut(); - detach_node(node); - attach_before(node, (*self.values.as_ptr()).links.value.next); - } - } - - #[inline] - pub fn replace_value(&mut self, value: V) -> V { - unsafe { - let mut node = *self.entry.key_mut(); - mem::replace(&mut node.as_mut().entry_mut().1, value) - } - } - - #[inline] - pub fn replace_key(&mut self, key: K) -> K { - unsafe { - let mut node = *self.entry.key_mut(); - mem::replace(&mut node.as_mut().entry_mut().0, key) - } - } - - #[inline] - pub fn remove(self) -> V { - self.remove_entry().1 - } - - #[inline] - pub fn remove_entry(self) -> (K, V) { - let node = self.entry.remove_entry().0; - unsafe { remove_node(self.free, node) } - } -} - -pub struct RawVacantEntryMut<'a, K, V, S> { - hash_builder: &'a S, - values: &'a mut Option>>, - free: &'a mut Option>>, - entry: hash_map::RawVacantEntryMut<'a, NonNull>, (), NullHasher>, -} - -impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { - #[inline] - pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) - where - K: Hash, - S: BuildHasher, - { - let hash = hash_key(self.hash_builder, &key); - self.insert_hashed_nocheck(hash, key, value) - } - - #[inline] - pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) - where - K: Hash, - S: BuildHasher, - { - let hash_builder = self.hash_builder; - self.insert_with_hasher(hash, key, value, |k| hash_key(hash_builder, k)) - } - - #[inline] - pub fn insert_with_hasher( - self, - hash: u64, - key: K, - value: V, - hasher: impl Fn(&K) -> u64, - ) -> (&'a mut K, &'a mut V) - where - S: BuildHasher, - { - unsafe { - ensure_guard_node(self.values); - let mut new_node = allocate_node(self.free); - new_node.as_mut().put_entry((key, value)); - attach_before(new_node, NonNull::new_unchecked(self.values.as_ptr())); - - let node = *self - .entry - .insert_with_hasher(hash, new_node, (), move |k| hasher((*k).as_ref().key_ref())) - .0; - - let (key, value) = (*node.as_ptr()).entry_mut(); - (key, value) - } - } -} - -impl fmt::Debug for RawEntryBuilderMut<'_, K, V, S> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RawEntryBuilder").finish() - } -} - -impl fmt::Debug for RawEntryMut<'_, K, V, S> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), - RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), - } - } -} - -impl fmt::Debug for RawOccupiedEntryMut<'_, K, V> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RawOccupiedEntryMut") - .field("key", self.key()) - .field("value", self.get()) - .finish() - } -} - -impl fmt::Debug for RawVacantEntryMut<'_, K, V, S> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RawVacantEntryMut").finish() - } -} - -impl fmt::Debug for RawEntryBuilder<'_, K, V, S> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RawEntryBuilder").finish() - } -} - -unsafe impl<'a, K, V> Send for RawOccupiedEntryMut<'a, K, V> -where - K: Send, - V: Send, -{ -} - -unsafe impl<'a, K, V> Sync for RawOccupiedEntryMut<'a, K, V> -where - K: Sync, - V: Sync, -{ -} - -unsafe impl<'a, K, V, S> Send for RawVacantEntryMut<'a, K, V, S> -where - K: Send, - V: Send, - S: Send, -{ -} - -unsafe impl<'a, K, V, S> Sync for RawVacantEntryMut<'a, K, V, S> -where - K: Sync, - V: Sync, - S: Sync, -{ -} - -pub struct Iter<'a, K, V> { - head: *const Node, - tail: *const Node, - remaining: usize, - marker: PhantomData<(&'a K, &'a V)>, -} - -pub struct IterMut<'a, K, V> { - head: Option>>, - tail: Option>>, - remaining: usize, - marker: PhantomData<(&'a K, &'a mut V)>, -} - -pub struct IntoIter { - head: Option>>, - tail: Option>>, - remaining: usize, - marker: PhantomData<(K, V)>, -} - -pub struct Drain<'a, K, V> { - free: NonNull>>>, - head: Option>>, - tail: Option>>, - remaining: usize, - // We want `Drain` to be covariant - marker: PhantomData<(K, V, &'a LinkedHashMap)>, -} - -impl IterMut<'_, K, V> { - #[inline] - pub(crate) fn iter(&self) -> Iter<'_, K, V> { - Iter { - head: self.head.as_ptr(), - tail: self.tail.as_ptr(), - remaining: self.remaining, - marker: PhantomData, - } - } -} - -impl IntoIter { - #[inline] - pub(crate) fn iter(&self) -> Iter<'_, K, V> { - Iter { - head: self.head.as_ptr(), - tail: self.tail.as_ptr(), - remaining: self.remaining, - marker: PhantomData, - } - } -} - -impl Drain<'_, K, V> { - #[inline] - pub(crate) fn iter(&self) -> Iter<'_, K, V> { - Iter { - head: self.head.as_ptr(), - tail: self.tail.as_ptr(), - remaining: self.remaining, - marker: PhantomData, - } - } -} - -unsafe impl<'a, K, V> Send for Iter<'a, K, V> -where - K: Send, - V: Send, -{ -} - -unsafe impl<'a, K, V> Send for IterMut<'a, K, V> -where - K: Send, - V: Send, -{ -} - -unsafe impl Send for IntoIter -where - K: Send, - V: Send, -{ -} - -unsafe impl<'a, K, V> Send for Drain<'a, K, V> -where - K: Send, - V: Send, -{ -} - -unsafe impl<'a, K, V> Sync for Iter<'a, K, V> -where - K: Sync, - V: Sync, -{ -} - -unsafe impl<'a, K, V> Sync for IterMut<'a, K, V> -where - K: Sync, - V: Sync, -{ -} - -unsafe impl Sync for IntoIter -where - K: Sync, - V: Sync, -{ -} - -unsafe impl<'a, K, V> Sync for Drain<'a, K, V> -where - K: Sync, - V: Sync, -{ -} - -impl<'a, K, V> Clone for Iter<'a, K, V> { - #[inline] - fn clone(&self) -> Self { - Iter { ..*self } - } -} - -impl fmt::Debug for Iter<'_, K, V> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl fmt::Debug for IterMut<'_, K, V> -where - K: fmt::Debug, - V: fmt::Debug, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.iter()).finish() - } -} - -impl fmt::Debug for IntoIter -where - K: fmt::Debug, - V: fmt::Debug, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.iter()).finish() - } -} - -impl fmt::Debug for Drain<'_, K, V> -where - K: fmt::Debug, - V: fmt::Debug, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.iter()).finish() - } -} - -impl<'a, K, V> Iterator for Iter<'a, K, V> { - type Item = (&'a K, &'a V); - - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a V)> { - if self.remaining == 0 { - None - } else { - self.remaining -= 1; - unsafe { - let (key, value) = (*self.head).entry_ref(); - self.head = (*self.head).links.value.next.as_ptr(); - Some((key, value)) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.remaining, Some(self.remaining)) - } -} - -impl<'a, K, V> Iterator for IterMut<'a, K, V> { - type Item = (&'a K, &'a mut V); - - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - if self.remaining == 0 { - None - } else { - self.remaining -= 1; - unsafe { - let head = self.head.as_ptr(); - let (key, value) = (*head).entry_mut(); - self.head = Some((*head).links.value.next); - Some((key, value)) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.remaining, Some(self.remaining)) - } -} - -impl Iterator for IntoIter { - type Item = (K, V); - - #[inline] - fn next(&mut self) -> Option<(K, V)> { - if self.remaining == 0 { - return None; - } - self.remaining -= 1; - unsafe { - let head = self.head.as_ptr(); - self.head = Some((*head).links.value.next); - let mut e = Box::from_raw(head); - Some(e.take_entry()) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.remaining, Some(self.remaining)) - } -} - -impl<'a, K, V> Iterator for Drain<'a, K, V> { - type Item = (K, V); - - #[inline] - fn next(&mut self) -> Option<(K, V)> { - if self.remaining == 0 { - return None; - } - self.remaining -= 1; - unsafe { - let mut head = NonNull::new_unchecked(self.head.as_ptr()); - self.head = Some(head.as_ref().links.value.next); - let entry = head.as_mut().take_entry(); - push_free(self.free.as_mut(), head); - Some(entry) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.remaining, Some(self.remaining)) - } -} - -impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> { - #[inline] - fn next_back(&mut self) -> Option<(&'a K, &'a V)> { - if self.remaining == 0 { - None - } else { - self.remaining -= 1; - unsafe { - let tail = self.tail; - self.tail = (*tail).links.value.prev.as_ptr(); - let (key, value) = (*tail).entry_ref(); - Some((key, value)) - } - } - } -} - -impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> { - #[inline] - fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { - if self.remaining == 0 { - None - } else { - self.remaining -= 1; - unsafe { - let tail = self.tail.as_ptr(); - self.tail = Some((*tail).links.value.prev); - let (key, value) = (*tail).entry_mut(); - Some((key, value)) - } - } - } -} - -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option<(K, V)> { - if self.remaining == 0 { - return None; - } - self.remaining -= 1; - unsafe { - let mut e = *Box::from_raw(self.tail.as_ptr()); - self.tail = Some(e.links.value.prev); - Some(e.take_entry()) - } - } -} - -impl<'a, K, V> DoubleEndedIterator for Drain<'a, K, V> { - #[inline] - fn next_back(&mut self) -> Option<(K, V)> { - if self.remaining == 0 { - return None; - } - self.remaining -= 1; - unsafe { - let mut tail = NonNull::new_unchecked(self.tail.as_ptr()); - self.tail = Some(tail.as_ref().links.value.prev); - let entry = tail.as_mut().take_entry(); - push_free(&mut *self.free.as_ptr(), tail); - Some(entry) - } - } -} - -impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {} - -impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {} - -impl ExactSizeIterator for IntoIter {} - -impl Drop for IntoIter { - #[inline] - fn drop(&mut self) { - for _ in 0..self.remaining { - unsafe { - let tail = self.tail.as_ptr(); - self.tail = Some((*tail).links.value.prev); - (*tail).take_entry(); - let _ = Box::from_raw(tail); - } - } - } -} - -impl<'a, K, V> Drop for Drain<'a, K, V> { - #[inline] - fn drop(&mut self) { - for _ in 0..self.remaining { - unsafe { - let mut tail = NonNull::new_unchecked(self.tail.as_ptr()); - self.tail = Some(tail.as_ref().links.value.prev); - tail.as_mut().take_entry(); - push_free(&mut *self.free.as_ptr(), tail); - } - } - } -} - -pub struct Keys<'a, K, V> { - inner: Iter<'a, K, V>, -} - -impl fmt::Debug for Keys<'_, K, V> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl<'a, K, V> Clone for Keys<'a, K, V> { - #[inline] - fn clone(&self) -> Keys<'a, K, V> { - Keys { - inner: self.inner.clone(), - } - } -} - -impl<'a, K, V> Iterator for Keys<'a, K, V> { - type Item = &'a K; - - #[inline] - fn next(&mut self) -> Option<&'a K> { - self.inner.next().map(|e| e.0) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> { - #[inline] - fn next_back(&mut self) -> Option<&'a K> { - self.inner.next_back().map(|e| e.0) - } -} - -impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -pub struct Values<'a, K, V> { - inner: Iter<'a, K, V>, -} - -impl Clone for Values<'_, K, V> { - #[inline] - fn clone(&self) -> Self { - Values { - inner: self.inner.clone(), - } - } -} - -impl fmt::Debug for Values<'_, K, V> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl<'a, K, V> Iterator for Values<'a, K, V> { - type Item = &'a V; - - #[inline] - fn next(&mut self) -> Option<&'a V> { - self.inner.next().map(|e| e.1) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> { - #[inline] - fn next_back(&mut self) -> Option<&'a V> { - self.inner.next_back().map(|e| e.1) - } -} - -impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -pub struct ValuesMut<'a, K, V> { - inner: IterMut<'a, K, V>, -} - -impl fmt::Debug for ValuesMut<'_, K, V> -where - K: fmt::Debug, - V: fmt::Debug, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.inner.iter()).finish() - } -} - -impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { - type Item = &'a mut V; - - #[inline] - fn next(&mut self) -> Option<&'a mut V> { - self.inner.next().map(|e| e.1) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl<'a, K, V> DoubleEndedIterator for ValuesMut<'a, K, V> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut V> { - self.inner.next_back().map(|e| e.1) - } -} - -impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -impl<'a, K, V, S> IntoIterator for &'a LinkedHashMap { - type Item = (&'a K, &'a V); - type IntoIter = Iter<'a, K, V>; - - #[inline] - fn into_iter(self) -> Iter<'a, K, V> { - self.iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a mut LinkedHashMap { - type Item = (&'a K, &'a mut V); - type IntoIter = IterMut<'a, K, V>; - - #[inline] - fn into_iter(self) -> IterMut<'a, K, V> { - self.iter_mut() - } -} - -impl IntoIterator for LinkedHashMap { - type Item = (K, V); - type IntoIter = IntoIter; - - #[inline] - fn into_iter(mut self) -> IntoIter { - unsafe { - let (head, tail) = if let Some(values) = self.values { - let ValueLinks { - next: head, - prev: tail, - } = values.as_ref().links.value; - - let _ = Box::from_raw(self.values.as_ptr()); - self.values = None; - - (Some(head), Some(tail)) - } else { - (None, None) - }; - let len = self.len(); - - drop_free_nodes(self.free); - self.free = None; - - self.map.clear(); - - IntoIter { - head, - tail, - remaining: len, - marker: PhantomData, - } - } - } -} - -// A ZST that asserts that the inner HashMap will not do its own key hashing -struct NullHasher; - -impl BuildHasher for NullHasher { - type Hasher = Self; - - #[inline] - fn build_hasher(&self) -> Self { - Self - } -} - -impl Hasher for NullHasher { - #[inline] - fn write(&mut self, _bytes: &[u8]) { - unreachable!("inner map should not be using its built-in hasher") - } - - #[inline] - fn finish(&self) -> u64 { - unreachable!("inner map should not be using its built-in hasher") - } -} - -struct ValueLinks { - next: NonNull>, - prev: NonNull>, -} - -impl Clone for ValueLinks { - #[inline] - fn clone(&self) -> Self { - ValueLinks { - next: self.next, - prev: self.prev, - } - } -} - -impl Copy for ValueLinks {} - -struct FreeLink { - next: Option>>, -} - -impl Clone for FreeLink { - #[inline] - fn clone(&self) -> Self { - FreeLink { next: self.next } - } -} - -impl Copy for FreeLink {} - -union Links { - value: ValueLinks, - free: FreeLink, -} - -struct Node { - entry: MaybeUninit<(K, V)>, - links: Links, -} - -impl Node { - #[inline] - unsafe fn put_entry(&mut self, entry: (K, V)) { - self.entry.as_mut_ptr().write(entry) - } - - #[inline] - unsafe fn entry_ref(&self) -> &(K, V) { - &*self.entry.as_ptr() - } - - #[inline] - unsafe fn key_ref(&self) -> &K { - &(*self.entry.as_ptr()).0 - } - - #[inline] - unsafe fn entry_mut(&mut self) -> &mut (K, V) { - &mut *self.entry.as_mut_ptr() - } - - #[inline] - unsafe fn take_entry(&mut self) -> (K, V) { - self.entry.as_ptr().read() - } -} - -trait OptNonNullExt { - fn as_ptr(self) -> *mut T; -} - -impl OptNonNullExt for Option> { - #[inline] - fn as_ptr(self) -> *mut T { - match self { - Some(ptr) => ptr.as_ptr(), - None => ptr::null_mut(), - } - } -} - -// Allocate a circular list guard node if not present. -#[inline] -unsafe fn ensure_guard_node(head: &mut Option>>) { - if head.is_none() { - let mut p = NonNull::new_unchecked(Box::into_raw(Box::new(Node { - entry: MaybeUninit::uninit(), - links: Links { - value: ValueLinks { - next: NonNull::dangling(), - prev: NonNull::dangling(), - }, - }, - }))); - p.as_mut().links.value = ValueLinks { next: p, prev: p }; - *head = Some(p); - } -} - -// Attach the `to_attach` node to the existing circular list *before* `node`. -#[inline] -unsafe fn attach_before(mut to_attach: NonNull>, mut node: NonNull>) { - to_attach.as_mut().links.value = ValueLinks { - prev: node.as_ref().links.value.prev, - next: node, - }; - node.as_mut().links.value.prev = to_attach; - (*to_attach.as_mut().links.value.prev.as_ptr()) - .links - .value - .next = to_attach; -} - -#[inline] -unsafe fn detach_node(mut node: NonNull>) { - node.as_mut().links.value.prev.as_mut().links.value.next = node.as_ref().links.value.next; - node.as_mut().links.value.next.as_mut().links.value.prev = node.as_ref().links.value.prev; -} - -#[inline] -unsafe fn push_free( - free_list: &mut Option>>, - mut node: NonNull>, -) { - node.as_mut().links.free.next = *free_list; - *free_list = Some(node); -} - -#[inline] -unsafe fn pop_free( - free_list: &mut Option>>, -) -> Option>> { - if let Some(free) = *free_list { - *free_list = free.as_ref().links.free.next; - Some(free) - } else { - None - } -} - -#[inline] -unsafe fn allocate_node(free_list: &mut Option>>) -> NonNull> { - if let Some(mut free) = pop_free(free_list) { - free.as_mut().links.value = ValueLinks { - next: NonNull::dangling(), - prev: NonNull::dangling(), - }; - free - } else { - NonNull::new_unchecked(Box::into_raw(Box::new(Node { - entry: MaybeUninit::uninit(), - links: Links { - value: ValueLinks { - next: NonNull::dangling(), - prev: NonNull::dangling(), - }, - }, - }))) - } -} - -// Given node is assumed to be the guard node and is *not* dropped. -#[inline] -unsafe fn drop_value_nodes(guard: NonNull>) { - let mut cur = guard.as_ref().links.value.prev; - while cur != guard { - let prev = cur.as_ref().links.value.prev; - cur.as_mut().take_entry(); - let _ = Box::from_raw(cur.as_ptr()); - cur = prev; - } -} - -// Drops all linked free nodes starting with the given node. Free nodes are only non-circular -// singly linked, and should have uninitialized keys / values. -#[inline] -unsafe fn drop_free_nodes(mut free: Option>>) { - while let Some(some_free) = free { - let next_free = some_free.as_ref().links.free.next; - let _ = Box::from_raw(some_free.as_ptr()); - free = next_free; - } -} - -#[inline] -unsafe fn remove_node( - free_list: &mut Option>>, - mut node: NonNull>, -) -> (K, V) { - detach_node(node); - push_free(free_list, node); - node.as_mut().take_entry() -} - -#[inline] -fn hash_key(s: &S, k: &Q) -> u64 -where - S: BuildHasher, - Q: Hash + ?Sized, -{ - let mut hasher = s.build_hasher(); - k.hash(&mut hasher); - hasher.finish() -} - -// We do not drop the key and value when a value is filtered from the map during the call to -// `retain`. We need to be very careful not to have a live `HashMap` entry pointing to -// either a dangling `Node` or a `Node` with dropped keys / values. Since the key and value -// types may panic on drop, they may short-circuit the entry in the map actually being -// removed. Instead, we push the removed nodes onto the free list eagerly, then try and -// drop the keys and values for any newly freed nodes *after* `HashMap::retain` has -// completely finished. -struct DropFilteredValues<'a, K, V> { - free: &'a mut Option>>, - cur_free: Option>>, -} - -impl<'a, K, V> DropFilteredValues<'a, K, V> { - #[inline] - fn drop_later(&mut self, node: NonNull>) { - unsafe { - detach_node(node); - push_free(&mut self.cur_free, node); - } - } -} - -impl<'a, K, V> Drop for DropFilteredValues<'a, K, V> { - fn drop(&mut self) { - unsafe { - let end_free = self.cur_free; - while self.cur_free != *self.free { - let cur_free = self.cur_free.as_ptr(); - (*cur_free).take_entry(); - self.cur_free = (*cur_free).links.free.next; - } - *self.free = end_free; - } - } -} diff --git a/third-party/vendor/hashlink/src/linked_hash_set.rs b/third-party/vendor/hashlink/src/linked_hash_set.rs deleted file mode 100644 index b3361fb5..00000000 --- a/third-party/vendor/hashlink/src/linked_hash_set.rs +++ /dev/null @@ -1,766 +0,0 @@ -use core::{ - borrow::Borrow, - fmt, - hash::{BuildHasher, Hash, Hasher}, - iter::{Chain, FromIterator}, - ops::{BitAnd, BitOr, BitXor, Sub}, -}; - -use hashbrown::hash_map::DefaultHashBuilder; - -use crate::linked_hash_map::{self, LinkedHashMap, TryReserveError}; - -pub struct LinkedHashSet { - map: LinkedHashMap, -} - -impl LinkedHashSet { - #[inline] - pub fn new() -> LinkedHashSet { - LinkedHashSet { - map: LinkedHashMap::new(), - } - } - - #[inline] - pub fn with_capacity(capacity: usize) -> LinkedHashSet { - LinkedHashSet { - map: LinkedHashMap::with_capacity(capacity), - } - } -} - -impl LinkedHashSet { - #[inline] - pub fn capacity(&self) -> usize { - self.map.capacity() - } - - #[inline] - pub fn iter(&self) -> Iter<'_, T> { - Iter { - iter: self.map.keys(), - } - } - - #[inline] - pub fn len(&self) -> usize { - self.map.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.map.is_empty() - } - - #[inline] - pub fn drain(&mut self) -> Drain { - Drain { - iter: self.map.drain(), - } - } - - #[inline] - pub fn clear(&mut self) { - self.map.clear() - } - - #[inline] - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - self.map.retain(|k, _| f(k)); - } -} - -impl LinkedHashSet -where - T: Eq + Hash, - S: BuildHasher, -{ - #[inline] - pub fn with_hasher(hasher: S) -> LinkedHashSet { - LinkedHashSet { - map: LinkedHashMap::with_hasher(hasher), - } - } - - #[inline] - pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> LinkedHashSet { - LinkedHashSet { - map: LinkedHashMap::with_capacity_and_hasher(capacity, hasher), - } - } - - #[inline] - pub fn hasher(&self) -> &S { - self.map.hasher() - } - - #[inline] - pub fn reserve(&mut self, additional: usize) { - self.map.reserve(additional) - } - - #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.map.try_reserve(additional) - } - - #[inline] - pub fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit() - } - - #[inline] - pub fn difference<'a>(&'a self, other: &'a LinkedHashSet) -> Difference<'a, T, S> { - Difference { - iter: self.iter(), - other, - } - } - - #[inline] - pub fn symmetric_difference<'a>( - &'a self, - other: &'a LinkedHashSet, - ) -> SymmetricDifference<'a, T, S> { - SymmetricDifference { - iter: self.difference(other).chain(other.difference(self)), - } - } - - #[inline] - pub fn intersection<'a>(&'a self, other: &'a LinkedHashSet) -> Intersection<'a, T, S> { - Intersection { - iter: self.iter(), - other, - } - } - - #[inline] - pub fn union<'a>(&'a self, other: &'a LinkedHashSet) -> Union<'a, T, S> { - Union { - iter: self.iter().chain(other.difference(self)), - } - } - - #[inline] - pub fn contains(&self, value: &Q) -> bool - where - T: Borrow, - Q: Hash + Eq, - { - self.map.contains_key(value) - } - - #[inline] - pub fn get(&self, value: &Q) -> Option<&T> - where - T: Borrow, - Q: Hash + Eq, - { - self.map.raw_entry().from_key(value).map(|p| p.0) - } - - #[inline] - pub fn get_or_insert(&mut self, value: T) -> &T { - self.map - .raw_entry_mut() - .from_key(&value) - .or_insert(value, ()) - .0 - } - - #[inline] - pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T - where - T: Borrow, - Q: Hash + Eq, - F: FnOnce(&Q) -> T, - { - self.map - .raw_entry_mut() - .from_key(value) - .or_insert_with(|| (f(value), ())) - .0 - } - - #[inline] - pub fn is_disjoint(&self, other: &LinkedHashSet) -> bool { - self.iter().all(|v| !other.contains(v)) - } - - #[inline] - pub fn is_subset(&self, other: &LinkedHashSet) -> bool { - self.iter().all(|v| other.contains(v)) - } - - #[inline] - pub fn is_superset(&self, other: &LinkedHashSet) -> bool { - other.is_subset(self) - } - - /// Inserts the given value into the set. - /// - /// If the set did not have this value present, inserts it at the *back* of the internal linked - /// list and returns true, otherwise it moves the existing value to the *back* of the internal - /// linked list and returns false. - #[inline] - pub fn insert(&mut self, value: T) -> bool { - self.map.insert(value, ()).is_none() - } - - /// Adds the given value to the set, replacing the existing value. - /// - /// If a previous value existed, returns the replaced value. In this case, the value's position - /// in the internal linked list is *not* changed. - #[inline] - pub fn replace(&mut self, value: T) -> Option { - match self.map.entry(value) { - linked_hash_map::Entry::Occupied(occupied) => Some(occupied.replace_key()), - linked_hash_map::Entry::Vacant(vacant) => { - vacant.insert(()); - None - } - } - } - - #[inline] - pub fn remove(&mut self, value: &Q) -> bool - where - T: Borrow, - Q: Hash + Eq, - { - self.map.remove(value).is_some() - } - - #[inline] - pub fn take(&mut self, value: &Q) -> Option - where - T: Borrow, - Q: Hash + Eq, - { - match self.map.raw_entry_mut().from_key(value) { - linked_hash_map::RawEntryMut::Occupied(occupied) => Some(occupied.remove_entry().0), - linked_hash_map::RawEntryMut::Vacant(_) => None, - } - } - - #[inline] - pub fn front(&self) -> Option<&T> { - self.map.front().map(|(k, _)| k) - } - - #[inline] - pub fn pop_front(&mut self) -> Option { - self.map.pop_front().map(|(k, _)| k) - } - - #[inline] - pub fn back(&self) -> Option<&T> { - self.map.back().map(|(k, _)| k) - } - - #[inline] - pub fn pop_back(&mut self) -> Option { - self.map.pop_back().map(|(k, _)| k) - } - - #[inline] - pub fn to_front(&mut self, value: &Q) -> bool - where - T: Borrow, - Q: Hash + Eq, - { - match self.map.raw_entry_mut().from_key(value) { - linked_hash_map::RawEntryMut::Occupied(mut occupied) => { - occupied.to_front(); - true - } - linked_hash_map::RawEntryMut::Vacant(_) => false, - } - } - - #[inline] - pub fn to_back(&mut self, value: &Q) -> bool - where - T: Borrow, - Q: Hash + Eq, - { - match self.map.raw_entry_mut().from_key(value) { - linked_hash_map::RawEntryMut::Occupied(mut occupied) => { - occupied.to_back(); - true - } - linked_hash_map::RawEntryMut::Vacant(_) => false, - } - } - - #[inline] - pub fn retain_with_order(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - self.map.retain_with_order(|k, _| f(k)); - } -} - -impl Clone for LinkedHashSet { - #[inline] - fn clone(&self) -> Self { - let map = self.map.clone(); - Self { map } - } -} - -impl PartialEq for LinkedHashSet -where - T: Eq + Hash, - S: BuildHasher, -{ - #[inline] - fn eq(&self, other: &Self) -> bool { - self.len() == other.len() && self.iter().eq(other) - } -} - -impl Hash for LinkedHashSet -where - T: Eq + Hash, - S: BuildHasher, -{ - #[inline] - fn hash(&self, state: &mut H) { - for e in self { - e.hash(state); - } - } -} - -impl Eq for LinkedHashSet -where - T: Eq + Hash, - S: BuildHasher, -{ -} - -impl fmt::Debug for LinkedHashSet -where - T: fmt::Debug, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_set().entries(self.iter()).finish() - } -} - -impl FromIterator for LinkedHashSet -where - T: Eq + Hash, - S: BuildHasher + Default, -{ - #[inline] - fn from_iter>(iter: I) -> LinkedHashSet { - let mut set = LinkedHashSet::with_hasher(Default::default()); - set.extend(iter); - set - } -} - -impl Extend for LinkedHashSet -where - T: Eq + Hash, - S: BuildHasher, -{ - #[inline] - fn extend>(&mut self, iter: I) { - self.map.extend(iter.into_iter().map(|k| (k, ()))); - } -} - -impl<'a, T, S> Extend<&'a T> for LinkedHashSet -where - T: 'a + Eq + Hash + Copy, - S: BuildHasher, -{ - #[inline] - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} - -impl Default for LinkedHashSet -where - S: Default, -{ - #[inline] - fn default() -> LinkedHashSet { - LinkedHashSet { - map: LinkedHashMap::default(), - } - } -} - -impl<'a, 'b, T, S> BitOr<&'b LinkedHashSet> for &'a LinkedHashSet -where - T: Eq + Hash + Clone, - S: BuildHasher + Default, -{ - type Output = LinkedHashSet; - - #[inline] - fn bitor(self, rhs: &LinkedHashSet) -> LinkedHashSet { - self.union(rhs).cloned().collect() - } -} - -impl<'a, 'b, T, S> BitAnd<&'b LinkedHashSet> for &'a LinkedHashSet -where - T: Eq + Hash + Clone, - S: BuildHasher + Default, -{ - type Output = LinkedHashSet; - - #[inline] - fn bitand(self, rhs: &LinkedHashSet) -> LinkedHashSet { - self.intersection(rhs).cloned().collect() - } -} - -impl<'a, 'b, T, S> BitXor<&'b LinkedHashSet> for &'a LinkedHashSet -where - T: Eq + Hash + Clone, - S: BuildHasher + Default, -{ - type Output = LinkedHashSet; - - #[inline] - fn bitxor(self, rhs: &LinkedHashSet) -> LinkedHashSet { - self.symmetric_difference(rhs).cloned().collect() - } -} - -impl<'a, 'b, T, S> Sub<&'b LinkedHashSet> for &'a LinkedHashSet -where - T: Eq + Hash + Clone, - S: BuildHasher + Default, -{ - type Output = LinkedHashSet; - - #[inline] - fn sub(self, rhs: &LinkedHashSet) -> LinkedHashSet { - self.difference(rhs).cloned().collect() - } -} - -pub struct Iter<'a, K> { - iter: linked_hash_map::Keys<'a, K, ()>, -} - -pub struct IntoIter { - iter: linked_hash_map::IntoIter, -} - -pub struct Drain<'a, K: 'a> { - iter: linked_hash_map::Drain<'a, K, ()>, -} - -pub struct Intersection<'a, T, S> { - iter: Iter<'a, T>, - other: &'a LinkedHashSet, -} - -pub struct Difference<'a, T, S> { - iter: Iter<'a, T>, - other: &'a LinkedHashSet, -} - -pub struct SymmetricDifference<'a, T, S> { - iter: Chain, Difference<'a, T, S>>, -} - -pub struct Union<'a, T, S> { - iter: Chain, Difference<'a, T, S>>, -} - -impl<'a, T, S> IntoIterator for &'a LinkedHashSet { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - #[inline] - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -impl IntoIterator for LinkedHashSet { - type Item = T; - type IntoIter = IntoIter; - - #[inline] - fn into_iter(self) -> IntoIter { - IntoIter { - iter: self.map.into_iter(), - } - } -} - -impl<'a, K> Clone for Iter<'a, K> { - #[inline] - fn clone(&self) -> Iter<'a, K> { - Iter { - iter: self.iter.clone(), - } - } -} -impl<'a, K> Iterator for Iter<'a, K> { - type Item = &'a K; - - #[inline] - fn next(&mut self) -> Option<&'a K> { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a, K> ExactSizeIterator for Iter<'a, K> {} - -impl<'a, T> DoubleEndedIterator for Iter<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a T> { - self.iter.next_back() - } -} - -impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl Iterator for IntoIter { - type Item = K; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for IntoIter {} - -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(|(k, _)| k) - } -} - -impl<'a, K> Iterator for Drain<'a, K> { - type Item = K; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a, K> DoubleEndedIterator for Drain<'a, K> { - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(|(k, _)| k) - } -} - -impl<'a, K> ExactSizeIterator for Drain<'a, K> {} - -impl<'a, T, S> Clone for Intersection<'a, T, S> { - #[inline] - fn clone(&self) -> Intersection<'a, T, S> { - Intersection { - iter: self.iter.clone(), - ..*self - } - } -} - -impl<'a, T, S> Iterator for Intersection<'a, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - type Item = &'a T; - - #[inline] - fn next(&mut self) -> Option<&'a T> { - loop { - match self.iter.next() { - None => return None, - Some(elt) => { - if self.other.contains(elt) { - return Some(elt); - } - } - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } -} - -impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> -where - T: fmt::Debug + Eq + Hash, - S: BuildHasher, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl<'a, T, S> Clone for Difference<'a, T, S> { - #[inline] - fn clone(&self) -> Difference<'a, T, S> { - Difference { - iter: self.iter.clone(), - ..*self - } - } -} - -impl<'a, T, S> Iterator for Difference<'a, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - type Item = &'a T; - - #[inline] - fn next(&mut self) -> Option<&'a T> { - loop { - match self.iter.next() { - None => return None, - Some(elt) => { - if !self.other.contains(elt) { - return Some(elt); - } - } - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } -} - -impl<'a, T, S> fmt::Debug for Difference<'a, T, S> -where - T: fmt::Debug + Eq + Hash, - S: BuildHasher, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> { - #[inline] - fn clone(&self) -> SymmetricDifference<'a, T, S> { - SymmetricDifference { - iter: self.iter.clone(), - } - } -} - -impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - type Item = &'a T; - - #[inline] - fn next(&mut self) -> Option<&'a T> { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S> -where - T: fmt::Debug + Eq + Hash, - S: BuildHasher, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl<'a, T, S> Clone for Union<'a, T, S> { - #[inline] - fn clone(&self) -> Union<'a, T, S> { - Union { - iter: self.iter.clone(), - } - } -} - -impl<'a, T, S> fmt::Debug for Union<'a, T, S> -where - T: fmt::Debug + Eq + Hash, - S: BuildHasher, -{ - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.clone()).finish() - } -} - -impl<'a, T, S> Iterator for Union<'a, T, S> -where - T: Eq + Hash, - S: BuildHasher, -{ - type Item = &'a T; - - #[inline] - fn next(&mut self) -> Option<&'a T> { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} diff --git a/third-party/vendor/hashlink/src/lru_cache.rs b/third-party/vendor/hashlink/src/lru_cache.rs deleted file mode 100644 index 9ef36b5b..00000000 --- a/third-party/vendor/hashlink/src/lru_cache.rs +++ /dev/null @@ -1,292 +0,0 @@ -use core::{ - borrow::Borrow, - fmt, - hash::{BuildHasher, Hash}, - usize, -}; - -use hashbrown::hash_map; - -use crate::linked_hash_map::{self, LinkedHashMap}; - -pub use crate::linked_hash_map::{ - Drain, Entry, IntoIter, Iter, IterMut, OccupiedEntry, RawEntryBuilder, RawEntryBuilderMut, - RawOccupiedEntryMut, RawVacantEntryMut, VacantEntry, -}; - -pub struct LruCache { - map: LinkedHashMap, - max_size: usize, -} - -impl LruCache { - #[inline] - pub fn new(capacity: usize) -> Self { - LruCache { - map: LinkedHashMap::new(), - max_size: capacity, - } - } - - /// Create a new unbounded `LruCache` that does not automatically evict entries. - /// - /// A simple convenience method that is equivalent to `LruCache::new(usize::MAX)` - #[inline] - pub fn new_unbounded() -> Self { - LruCache::new(usize::MAX) - } -} - -impl LruCache { - #[inline] - pub fn with_hasher(capacity: usize, hash_builder: S) -> Self { - LruCache { - map: LinkedHashMap::with_hasher(hash_builder), - max_size: capacity, - } - } - - #[inline] - pub fn capacity(&self) -> usize { - self.max_size - } - - #[inline] - pub fn len(&self) -> usize { - self.map.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.map.is_empty() - } - - #[inline] - pub fn clear(&mut self) { - self.map.clear(); - } - - #[inline] - pub fn iter(&self) -> Iter { - self.map.iter() - } - - #[inline] - pub fn iter_mut(&mut self) -> IterMut { - self.map.iter_mut() - } - - #[inline] - pub fn drain(&mut self) -> Drain { - self.map.drain() - } -} - -impl LruCache -where - S: BuildHasher, -{ - #[inline] - pub fn contains_key(&mut self, key: &Q) -> bool - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.get_mut(key).is_some() - } - - /// Insert a new value into the `LruCache`. - /// - /// If necessary, will remove the value at the front of the LRU list to make room. - #[inline] - pub fn insert(&mut self, k: K, v: V) -> Option { - let old_val = self.map.insert(k, v); - if self.len() > self.capacity() { - self.remove_lru(); - } - old_val - } - - /// Get the value for the given key, *without* marking the value as recently used and moving it - /// to the back of the LRU list. - #[inline] - pub fn peek(&self, k: &Q) -> Option<&V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.map.get(k) - } - - /// Get the value for the given key mutably, *without* marking the value as recently used and - /// moving it to the back of the LRU list. - #[inline] - pub fn peek_mut(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.map.get_mut(k) - } - - /// Retrieve the given key, marking it as recently used and moving it to the back of the LRU - /// list. - #[inline] - pub fn get(&mut self, k: &Q) -> Option<&V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.get_mut(k).map(|v| &*v) - } - - /// Retrieve the given key, marking it as recently used and moving it to the back of the LRU - /// list. - #[inline] - pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - match self.map.raw_entry_mut().from_key(k) { - linked_hash_map::RawEntryMut::Occupied(mut occupied) => { - occupied.to_back(); - Some(occupied.into_mut()) - } - linked_hash_map::RawEntryMut::Vacant(_) => None, - } - } - - /// If the returned entry is vacant, it will always have room to insert a single value. By - /// using the entry API, you can exceed the configured capacity by 1. - /// - /// The returned entry is not automatically moved to the back of the LRU list. By calling - /// `Entry::to_back` / `Entry::to_front` you can manually control the position of this entry in - /// the LRU list. - #[inline] - pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S> { - if self.len() > self.capacity() { - self.remove_lru(); - } - self.map.entry(key) - } - - /// The constructed raw entry is never automatically moved to the back of the LRU list. By - /// calling `Entry::to_back` / `Entry::to_front` you can manually control the position of this - /// entry in the LRU list. - #[inline] - pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> { - self.map.raw_entry() - } - - /// If the constructed raw entry is vacant, it will always have room to insert a single value. - /// By using the raw entry API, you can exceed the configured capacity by 1. - /// - /// The constructed raw entry is never automatically moved to the back of the LRU list. By - /// calling `Entry::to_back` / `Entry::to_front` you can manually control the position of this - /// entry in the LRU list. - #[inline] - pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S> { - if self.len() > self.capacity() { - self.remove_lru(); - } - self.map.raw_entry_mut() - } - - #[inline] - pub fn remove(&mut self, k: &Q) -> Option - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.map.remove(k) - } - - #[inline] - pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - self.map.remove_entry(k) - } - - /// Set the new cache capacity for the `LruCache`. - /// - /// If there are more entries in the `LruCache` than the new capacity will allow, they are - /// removed. - #[inline] - pub fn set_capacity(&mut self, capacity: usize) { - for _ in capacity..self.len() { - self.remove_lru(); - } - self.max_size = capacity; - } - - /// Remove the least recently used entry and return it. - /// - /// If the `LruCache` is empty this will return None. - #[inline] - pub fn remove_lru(&mut self) -> Option<(K, V)> { - self.map.pop_front() - } -} - -impl Clone for LruCache { - #[inline] - fn clone(&self) -> Self { - LruCache { - map: self.map.clone(), - max_size: self.max_size, - } - } -} - -impl Extend<(K, V)> for LruCache { - #[inline] - fn extend>(&mut self, iter: I) { - for (k, v) in iter { - self.insert(k, v); - } - } -} - -impl IntoIterator for LruCache { - type Item = (K, V); - type IntoIter = IntoIter; - - #[inline] - fn into_iter(self) -> IntoIter { - self.map.into_iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a LruCache { - type Item = (&'a K, &'a V); - type IntoIter = Iter<'a, K, V>; - - #[inline] - fn into_iter(self) -> Iter<'a, K, V> { - self.iter() - } -} - -impl<'a, K, V, S> IntoIterator for &'a mut LruCache { - type Item = (&'a K, &'a mut V); - type IntoIter = IterMut<'a, K, V>; - - #[inline] - fn into_iter(self) -> IterMut<'a, K, V> { - self.iter_mut() - } -} - -impl fmt::Debug for LruCache -where - K: fmt::Debug, - V: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_map().entries(self.iter().rev()).finish() - } -} diff --git a/third-party/vendor/hashlink/src/serde.rs b/third-party/vendor/hashlink/src/serde.rs deleted file mode 100644 index 57c3b167..00000000 --- a/third-party/vendor/hashlink/src/serde.rs +++ /dev/null @@ -1,161 +0,0 @@ -use core::{ - fmt::{self, Formatter}, - hash::{BuildHasher, Hash}, - marker::PhantomData, -}; - -use serde::{ - de::{MapAccess, SeqAccess, Visitor}, - ser::{SerializeMap, SerializeSeq}, - Deserialize, Deserializer, Serialize, Serializer, -}; - -use crate::{LinkedHashMap, LinkedHashSet}; - -// LinkedHashMap impls - -impl Serialize for LinkedHashMap -where - K: Serialize + Eq + Hash, - V: Serialize, - S: BuildHasher, -{ - #[inline] - fn serialize(&self, serializer: T) -> Result { - let mut map_serializer = serializer.serialize_map(Some(self.len()))?; - for (k, v) in self { - map_serializer.serialize_key(k)?; - map_serializer.serialize_value(v)?; - } - map_serializer.end() - } -} - -impl<'de, K, V, S> Deserialize<'de> for LinkedHashMap -where - K: Deserialize<'de> + Eq + Hash, - V: Deserialize<'de>, - S: BuildHasher + Default, -{ - fn deserialize>(deserializer: D) -> Result { - #[derive(Debug)] - pub struct LinkedHashMapVisitor { - marker: PhantomData>, - } - - impl LinkedHashMapVisitor { - fn new() -> Self { - LinkedHashMapVisitor { - marker: PhantomData, - } - } - } - - impl Default for LinkedHashMapVisitor { - fn default() -> Self { - Self::new() - } - } - - impl<'de, K, V, S> Visitor<'de> for LinkedHashMapVisitor - where - K: Deserialize<'de> + Eq + Hash, - V: Deserialize<'de>, - S: BuildHasher + Default, - { - type Value = LinkedHashMap; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - write!(formatter, "a map") - } - - #[inline] - fn visit_map>(self, mut map: M) -> Result { - let mut values = LinkedHashMap::with_capacity_and_hasher( - map.size_hint().unwrap_or(0), - S::default(), - ); - - while let Some((k, v)) = map.next_entry()? { - values.insert(k, v); - } - - Ok(values) - } - } - - deserializer.deserialize_map(LinkedHashMapVisitor::default()) - } -} - -// LinkedHashSet impls - -impl Serialize for LinkedHashSet -where - T: Serialize + Eq + Hash, - S: BuildHasher, -{ - #[inline] - fn serialize(&self, serializer: U) -> Result { - let mut seq_serializer = serializer.serialize_seq(Some(self.len()))?; - for v in self { - seq_serializer.serialize_element(v)?; - } - seq_serializer.end() - } -} - -impl<'de, T, S> Deserialize<'de> for LinkedHashSet -where - T: Deserialize<'de> + Eq + Hash, - S: BuildHasher + Default, -{ - fn deserialize>(deserializer: D) -> Result { - #[derive(Debug)] - pub struct LinkedHashSetVisitor { - marker: PhantomData>, - } - - impl LinkedHashSetVisitor { - fn new() -> Self { - LinkedHashSetVisitor { - marker: PhantomData, - } - } - } - - impl Default for LinkedHashSetVisitor { - fn default() -> Self { - Self::new() - } - } - - impl<'de, T, S> Visitor<'de> for LinkedHashSetVisitor - where - T: Deserialize<'de> + Eq + Hash, - S: BuildHasher + Default, - { - type Value = LinkedHashSet; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - write!(formatter, "a sequence") - } - - #[inline] - fn visit_seq>(self, mut seq: SA) -> Result { - let mut values = LinkedHashSet::with_capacity_and_hasher( - seq.size_hint().unwrap_or(0), - S::default(), - ); - - while let Some(v) = seq.next_element()? { - values.insert(v); - } - - Ok(values) - } - } - - deserializer.deserialize_seq(LinkedHashSetVisitor::default()) - } -} diff --git a/third-party/vendor/hashlink/tests/linked_hash_map.rs b/third-party/vendor/hashlink/tests/linked_hash_map.rs deleted file mode 100644 index e0462927..00000000 --- a/third-party/vendor/hashlink/tests/linked_hash_map.rs +++ /dev/null @@ -1,563 +0,0 @@ -use hashlink::{linked_hash_map, LinkedHashMap}; - -#[allow(dead_code)] -fn assert_covariance() { - fn set<'new>(v: LinkedHashMap<&'static str, ()>) -> LinkedHashMap<&'new str, ()> { - v - } - - fn iter<'a, 'new>( - v: linked_hash_map::Iter<'a, &'static str, &'static str>, - ) -> linked_hash_map::Iter<'a, &'new str, &'new str> { - v - } - - fn iter_mut<'a, 'new>( - v: linked_hash_map::Iter<'a, &'static str, ()>, - ) -> linked_hash_map::Iter<'a, &'new str, ()> { - v - } - - fn into_iter<'new>( - v: linked_hash_map::IntoIter<&'static str, &'static str>, - ) -> linked_hash_map::IntoIter<&'new str, &'new str> { - v - } - - fn drain<'new>( - d: linked_hash_map::Drain<'static, &'static str, &'static str>, - ) -> linked_hash_map::Drain<'new, &'new str, &'new str> { - d - } - - fn raw_entry_builder<'a, 'new>( - v: linked_hash_map::RawEntryBuilder<'a, &'static str, &'static str, ()>, - ) -> linked_hash_map::RawEntryBuilder<'a, &'new str, &'new str, ()> { - v - } -} - -#[test] -fn test_index() { - let mut map = LinkedHashMap::new(); - map.insert(1, 10); - map.insert(2, 20); - assert_eq!(10, map[&1]); - map[&2] = 22; - assert_eq!(22, map[&2]); -} - -#[test] -fn test_insert_and_get() { - let mut map = LinkedHashMap::new(); - map.insert(1, 10); - map.insert(2, 20); - assert_eq!(map.get(&1), Some(&10)); - assert_eq!(map.get(&2), Some(&20)); - assert_eq!(map.len(), 2); -} - -#[test] -fn test_insert_update() { - let mut map = LinkedHashMap::new(); - map.insert("1".to_string(), vec![10, 10]); - map.insert("1".to_string(), vec![10, 19]); - assert_eq!(map.get(&"1".to_string()), Some(&vec![10, 19])); - assert_eq!(map.len(), 1); -} - -#[test] -fn test_entry_insert_vacant() { - let mut map = LinkedHashMap::new(); - match map.entry("1".to_string()) { - linked_hash_map::Entry::Vacant(e) => { - assert_eq!(*e.insert(vec![10, 10]), vec![10, 10]); - } - _ => panic!("fail"), - } - assert!(map.contains_key("1")); - assert_eq!(map["1"], vec![10, 10]); - - match map.entry("1".to_string()) { - linked_hash_map::Entry::Occupied(mut e) => { - assert_eq!(*e.get(), vec![10, 10]); - assert_eq!(e.insert(vec![10, 16]), vec![10, 10]); - } - _ => panic!("fail"), - } - - assert!(map.contains_key("1")); - assert_eq!(map["1"], vec![10, 16]); - - match map.entry("1".to_string()) { - linked_hash_map::Entry::Occupied(e) => { - assert_eq!(e.remove(), vec![10, 16]); - } - _ => panic!("fail"), - } -} - -#[test] -fn test_remove() { - let mut map = LinkedHashMap::new(); - map.insert(1, 10); - map.insert(2, 20); - map.insert(3, 30); - map.insert(4, 40); - map.insert(5, 50); - map.remove(&3); - map.remove(&4); - assert!(map.get(&3).is_none()); - assert!(map.get(&4).is_none()); - map.insert(6, 60); - map.insert(7, 70); - map.insert(8, 80); - assert_eq!(map.get(&6), Some(&60)); - assert_eq!(map.get(&7), Some(&70)); - assert_eq!(map.get(&8), Some(&80)); -} - -#[test] -fn test_pop() { - let mut map = LinkedHashMap::new(); - map.insert(1, 10); - map.insert(2, 20); - map.insert(3, 30); - map.insert(4, 40); - map.insert(5, 50); - assert_eq!(map.pop_front(), Some((1, 10))); - assert!(map.get(&1).is_none()); - assert_eq!(map.pop_back(), Some((5, 50))); - assert!(map.get(&5).is_none()); - map.insert(6, 60); - map.insert(7, 70); - map.insert(8, 80); - assert_eq!(map.pop_front(), Some((2, 20))); - assert!(map.get(&2).is_none()); - assert_eq!(map.pop_back(), Some((8, 80))); - assert!(map.get(&8).is_none()); - map.insert(3, 30); - assert_eq!(map.pop_front(), Some((4, 40))); - assert!(map.get(&4).is_none()); - assert_eq!(map.pop_back(), Some((3, 30))); - assert!(map.get(&3).is_none()); -} - -#[test] -fn test_move() { - let to_back = |map: &mut LinkedHashMap<_, _>, key| match map.entry(key) { - linked_hash_map::Entry::Occupied(mut occupied) => occupied.to_back(), - linked_hash_map::Entry::Vacant(_) => panic!(), - }; - - let to_front = |map: &mut LinkedHashMap<_, _>, key| match map.entry(key) { - linked_hash_map::Entry::Occupied(mut occupied) => occupied.to_front(), - linked_hash_map::Entry::Vacant(_) => panic!(), - }; - - let mut map = LinkedHashMap::new(); - map.insert(1, 10); - map.insert(2, 20); - map.insert(3, 30); - map.insert(4, 40); - map.insert(5, 50); - - to_back(&mut map, 1); - assert_eq!(map.keys().copied().collect::>(), vec![2, 3, 4, 5, 1]); - - to_front(&mut map, 4); - assert_eq!(map.keys().copied().collect::>(), vec![4, 2, 3, 5, 1]); - - to_back(&mut map, 3); - assert_eq!(map.keys().copied().collect::>(), vec![4, 2, 5, 1, 3]); - - to_front(&mut map, 2); - assert_eq!(map.keys().copied().collect::>(), vec![2, 4, 5, 1, 3]); - - to_back(&mut map, 3); - assert_eq!(map.keys().copied().collect::>(), vec![2, 4, 5, 1, 3]); - - to_front(&mut map, 2); - assert_eq!(map.keys().copied().collect::>(), vec![2, 4, 5, 1, 3]); -} - -#[test] -fn test_clear() { - let mut map = LinkedHashMap::new(); - map.insert(1, 10); - map.insert(2, 20); - map.clear(); - assert!(map.get(&1).is_none()); - assert!(map.get(&2).is_none()); - assert!(map.is_empty()); -} - -#[test] -fn test_iter() { - let mut map = LinkedHashMap::new(); - - // empty iter - assert_eq!(None, map.iter().next()); - - map.insert("a", 10); - map.insert("b", 20); - map.insert("c", 30); - - // regular iter - let mut iter = map.iter(); - assert_eq!((&"a", &10), iter.next().unwrap()); - assert_eq!((&"b", &20), iter.next().unwrap()); - assert_eq!((&"c", &30), iter.next().unwrap()); - assert_eq!(None, iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = map.iter(); - assert_eq!((&"a", &10), iter.next().unwrap()); - let mut iclone = iter.clone(); - assert_eq!((&"b", &20), iter.next().unwrap()); - assert_eq!((&"b", &20), iclone.next().unwrap()); - assert_eq!((&"c", &30), iter.next().unwrap()); - assert_eq!((&"c", &30), iclone.next().unwrap()); - - // reversed iter - let mut rev_iter = map.iter().rev(); - assert_eq!((&"c", &30), rev_iter.next().unwrap()); - assert_eq!((&"b", &20), rev_iter.next().unwrap()); - assert_eq!((&"a", &10), rev_iter.next().unwrap()); - assert_eq!(None, rev_iter.next()); - assert_eq!(None, rev_iter.next()); - - // mixed - let mut mixed_iter = map.iter(); - assert_eq!((&"a", &10), mixed_iter.next().unwrap()); - assert_eq!((&"c", &30), mixed_iter.next_back().unwrap()); - assert_eq!((&"b", &20), mixed_iter.next().unwrap()); - assert_eq!(None, mixed_iter.next()); - assert_eq!(None, mixed_iter.next_back()); -} - -#[test] -fn test_borrow() { - #[derive(PartialEq, Eq, Hash)] - struct Foo(Bar); - #[derive(PartialEq, Eq, Hash)] - struct Bar(i32); - - impl ::std::borrow::Borrow for Foo { - fn borrow(&self) -> &Bar { - &self.0 - } - } - - let mut map = LinkedHashMap::new(); - map.insert(Foo(Bar(1)), "a"); - map.insert(Foo(Bar(2)), "b"); - - assert!(map.contains_key(&Bar(1))); - assert!(map.contains_key(&Bar(2))); - assert!(map.contains_key(&Foo(Bar(1)))); - assert!(map.contains_key(&Foo(Bar(2)))); - - assert_eq!(map.get(&Bar(1)), Some(&"a")); - assert_eq!(map.get(&Bar(2)), Some(&"b")); - assert_eq!(map.get(&Foo(Bar(1))), Some(&"a")); - assert_eq!(map.get(&Foo(Bar(2))), Some(&"b")); - - assert_eq!(map.get_mut(&Bar(1)), Some(&mut "a")); - assert_eq!(map.get_mut(&Bar(2)), Some(&mut "b")); - assert_eq!(map.get_mut(&Foo(Bar(1))), Some(&mut "a")); - assert_eq!(map.get_mut(&Foo(Bar(2))), Some(&mut "b")); - - assert_eq!(map[&Bar(1)], "a"); - assert_eq!(map[&Bar(2)], "b"); - assert_eq!(map[&Foo(Bar(1))], "a"); - assert_eq!(map[&Foo(Bar(2))], "b"); - - assert_eq!(map.remove(&Bar(1)), Some("a")); - assert_eq!(map.remove(&Bar(2)), Some("b")); - assert_eq!(map.remove(&Foo(Bar(1))), None); - assert_eq!(map.remove(&Foo(Bar(2))), None); -} - -#[test] -fn test_iter_mut() { - let mut map = LinkedHashMap::new(); - map.insert("a", 10); - map.insert("c", 30); - map.insert("b", 20); - - { - let mut iter = map.iter_mut(); - let entry = iter.next().unwrap(); - assert_eq!("a", *entry.0); - *entry.1 = 17; - - assert_eq!(format!("{:?}", iter), "[(\"c\", 30), (\"b\", 20)]"); - - // reverse iterator - let mut iter = iter.rev(); - let entry = iter.next().unwrap(); - assert_eq!("b", *entry.0); - *entry.1 = 23; - - let entry = iter.next().unwrap(); - assert_eq!("c", *entry.0); - assert_eq!(None, iter.next()); - assert_eq!(None, iter.next()); - } - - assert_eq!(17, map[&"a"]); - assert_eq!(23, map[&"b"]); -} - -#[test] -fn test_consuming_iter() { - let map = { - let mut map = LinkedHashMap::new(); - map.insert("a", 10); - map.insert("c", 30); - map.insert("b", 20); - map - }; - - let mut iter = map.into_iter(); - assert_eq!(Some(("a", 10)), iter.next()); - assert_eq!(Some(("b", 20)), iter.next_back()); - assert_eq!(iter.len(), 1); - assert_eq!(format!("{:?}", iter), "[(\"c\", 30)]"); - assert_eq!(Some(("c", 30)), iter.next()); - assert_eq!(None, iter.next()); -} - -#[test] -fn test_consuming_iter_empty() { - let map = LinkedHashMap::<&str, i32>::new(); - let mut iter = map.into_iter(); - assert_eq!(None, iter.next()); -} - -#[test] -fn test_consuming_iter_with_free_list() { - let mut map = LinkedHashMap::new(); - map.insert("a", 10); - map.insert("c", 30); - map.insert("b", 20); - map.remove("a"); - map.remove("b"); - - let mut iter = map.into_iter(); - assert_eq!(Some(("c", 30)), iter.next()); - assert_eq!(None, iter.next()); -} - -#[test] -fn test_into_iter_drop() { - struct Counter<'a>(&'a mut usize); - - impl<'a> Drop for Counter<'a> { - fn drop(&mut self) { - *self.0 += 1; - } - } - - let mut a = 0; - let mut b = 0; - let mut c = 0; - - { - let mut map = LinkedHashMap::new(); - map.insert("a", Counter(&mut a)); - map.insert("b", Counter(&mut b)); - map.insert("c", Counter(&mut c)); - - let mut iter = map.into_iter(); - assert_eq!(iter.next().map(|p| p.0), Some("a")); - assert_eq!(iter.next_back().map(|p| p.0), Some("c")); - } - - assert_eq!(a, 1); - assert_eq!(b, 1); - assert_eq!(c, 1); -} - -#[test] -fn test_drain() { - use std::{cell::Cell, rc::Rc}; - - struct Counter(Rc>); - - impl<'a> Drop for Counter { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - let mut map = LinkedHashMap::new(); - - let a = Rc::new(Cell::new(0)); - let b = Rc::new(Cell::new(0)); - let c = Rc::new(Cell::new(0)); - - map.insert("a", Counter(a.clone())); - map.insert("b", Counter(b.clone())); - map.insert("c", Counter(c.clone())); - - let mut iter = map.drain(); - assert_eq!(iter.next().map(|p| p.0), Some("a")); - assert_eq!(iter.next_back().map(|p| p.0), Some("c")); - assert_eq!(iter.next_back().map(|p| p.0), Some("b")); - assert!(iter.next().is_none()); - assert!(iter.next_back().is_none()); - - drop(iter); - assert_eq!(map.len(), 0); - - assert_eq!(a.get(), 1); - assert_eq!(b.get(), 1); - assert_eq!(c.get(), 1); - - map.insert("a", Counter(a.clone())); - map.insert("b", Counter(b.clone())); - map.insert("c", Counter(c.clone())); - - let mut iter = map.drain(); - assert_eq!(iter.next().map(|p| p.0), Some("a")); - assert_eq!(iter.next().map(|p| p.0), Some("b")); - assert_eq!(iter.next_back().map(|p| p.0), Some("c")); - assert!(iter.next().is_none()); - assert!(iter.next_back().is_none()); - - drop(iter); - assert_eq!(map.len(), 0); - - assert_eq!(a.get(), 2); - assert_eq!(b.get(), 2); - assert_eq!(c.get(), 2); - - map.insert("a", Counter(a.clone())); - map.insert("b", Counter(b.clone())); - map.insert("c", Counter(c.clone())); - - map.drain(); - assert_eq!(map.len(), 0); - - assert_eq!(a.get(), 3); - assert_eq!(b.get(), 3); - assert_eq!(c.get(), 3); -} - -#[test] -fn test_send_sync() { - fn is_send_sync() {} - - is_send_sync::>(); - is_send_sync::>(); - is_send_sync::>(); - is_send_sync::>(); - is_send_sync::>(); - is_send_sync::>(); - is_send_sync::>(); - is_send_sync::>(); - is_send_sync::>(); - is_send_sync::>(); -} - -#[test] -fn test_retain() { - use std::{cell::Cell, rc::Rc}; - - let xs = [1, 2, 3, 4, 5, 6]; - let mut map: LinkedHashMap = xs.iter().map(|i| (i.to_string(), *i)).collect(); - map.retain(|_, v| *v % 2 == 0); - assert_eq!(map.len(), 3); - assert!(map.contains_key("2")); - assert!(map.contains_key("4")); - assert!(map.contains_key("6")); - - struct Counter(Rc>); - - impl<'a> Drop for Counter { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - let c = Rc::new(Cell::new(0)); - - let mut map = LinkedHashMap::new(); - map.insert(1, Counter(Rc::clone(&c))); - map.insert(2, Counter(Rc::clone(&c))); - map.insert(3, Counter(Rc::clone(&c))); - map.insert(4, Counter(Rc::clone(&c))); - - map.retain(|k, _| *k % 2 == 0); - - assert!(c.get() == 2); - drop(map); - assert!(c.get() == 4); -} - -#[test] -fn test_order_equality() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut map1: LinkedHashMap = xs.iter().map(|i| (i.to_string(), *i)).collect(); - let mut map2: LinkedHashMap = xs.iter().map(|i| (i.to_string(), *i)).collect(); - - assert_eq!(map1, map2); - - map1.to_front("4"); - assert_ne!(map1, map2); - - map2.to_front("4"); - assert_eq!(map1, map2); -} - -#[test] -fn test_replace() { - let mut map = LinkedHashMap::new(); - - map.insert(1, 1); - map.insert(2, 2); - map.insert(3, 3); - map.insert(4, 4); - - assert!(map - .iter() - .map(|(k, v)| (*k, *v)) - .eq([(1, 1), (2, 2), (3, 3), (4, 4)].iter().copied())); - - map.insert(3, 5); - - assert!(map - .iter() - .map(|(k, v)| (*k, *v)) - .eq([(1, 1), (2, 2), (4, 4), (3, 5)].iter().copied())); - - map.replace(2, 6); - - assert!(map - .iter() - .map(|(k, v)| (*k, *v)) - .eq([(1, 1), (2, 6), (4, 4), (3, 5)].iter().copied())); -} - -#[test] -fn test_shrink_to_fit_resize() { - let mut map = LinkedHashMap::new(); - map.shrink_to_fit(); - - for i in 0..100 { - map.insert(i, i); - } - map.shrink_to_fit(); - - for _ in 0..50 { - map.pop_front(); - map.shrink_to_fit(); - } - - assert_eq!(map.len(), 50); - for i in 50..100 { - assert_eq!(map.get(&i).unwrap(), &i); - } -} diff --git a/third-party/vendor/hashlink/tests/linked_hash_set.rs b/third-party/vendor/hashlink/tests/linked_hash_set.rs deleted file mode 100644 index 7a9e33f9..00000000 --- a/third-party/vendor/hashlink/tests/linked_hash_set.rs +++ /dev/null @@ -1,543 +0,0 @@ -use hashbrown::hash_map::DefaultHashBuilder; -use hashlink::linked_hash_set::{self, LinkedHashSet}; - -#[allow(dead_code)] -fn assert_covariance() { - fn set<'new>(v: LinkedHashSet<&'static str>) -> LinkedHashSet<&'new str> { - v - } - - fn iter<'a, 'new>( - v: linked_hash_set::Iter<'a, &'static str>, - ) -> linked_hash_set::Iter<'a, &'new str> { - v - } - - fn into_iter<'new>( - v: linked_hash_set::IntoIter<&'static str>, - ) -> linked_hash_set::IntoIter<&'new str> { - v - } - - fn difference<'a, 'new>( - v: linked_hash_set::Difference<'a, &'static str, DefaultHashBuilder>, - ) -> linked_hash_set::Difference<'a, &'new str, DefaultHashBuilder> { - v - } - - fn symmetric_difference<'a, 'new>( - v: linked_hash_set::SymmetricDifference<'a, &'static str, DefaultHashBuilder>, - ) -> linked_hash_set::SymmetricDifference<'a, &'new str, DefaultHashBuilder> { - v - } - - fn intersection<'a, 'new>( - v: linked_hash_set::Intersection<'a, &'static str, DefaultHashBuilder>, - ) -> linked_hash_set::Intersection<'a, &'new str, DefaultHashBuilder> { - v - } - - fn union<'a, 'new>( - v: linked_hash_set::Union<'a, &'static str, DefaultHashBuilder>, - ) -> linked_hash_set::Union<'a, &'new str, DefaultHashBuilder> { - v - } - - fn drain<'new>( - d: linked_hash_set::Drain<'static, &'static str>, - ) -> linked_hash_set::Drain<'new, &'new str> { - d - } -} - -#[test] -fn test_zero_capacities() { - type HS = LinkedHashSet; - - let s = HS::new(); - assert_eq!(s.capacity(), 0); - - let s = HS::default(); - assert_eq!(s.capacity(), 0); - - let s = HS::with_hasher(DefaultHashBuilder::default()); - assert_eq!(s.capacity(), 0); - - let s = HS::with_capacity(0); - assert_eq!(s.capacity(), 0); - - let s = HS::with_capacity_and_hasher(0, DefaultHashBuilder::default()); - assert_eq!(s.capacity(), 0); - - let mut s = HS::new(); - s.insert(1); - s.insert(2); - s.remove(&1); - s.remove(&2); - s.shrink_to_fit(); - assert_eq!(s.capacity(), 0); - - let mut s = HS::new(); - s.reserve(0); - assert_eq!(s.capacity(), 0); -} - -#[test] -fn test_disjoint() { - let mut xs = LinkedHashSet::new(); - let mut ys = LinkedHashSet::new(); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(5)); - assert!(ys.insert(11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(7)); - assert!(xs.insert(19)); - assert!(xs.insert(4)); - assert!(ys.insert(2)); - assert!(ys.insert(-11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(ys.insert(7)); - assert!(!xs.is_disjoint(&ys)); - assert!(!ys.is_disjoint(&xs)); -} - -#[test] -fn test_subset_and_superset() { - let mut a = LinkedHashSet::new(); - assert!(a.insert(0)); - assert!(a.insert(5)); - assert!(a.insert(11)); - assert!(a.insert(7)); - - let mut b = LinkedHashSet::new(); - assert!(b.insert(0)); - assert!(b.insert(7)); - assert!(b.insert(19)); - assert!(b.insert(250)); - assert!(b.insert(11)); - assert!(b.insert(200)); - - assert!(!a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(!b.is_superset(&a)); - - assert!(b.insert(5)); - - assert!(a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(b.is_superset(&a)); -} - -#[test] -fn test_iterate() { - let mut a = LinkedHashSet::new(); - for i in 0..32 { - assert!(a.insert(i)); - } - let mut observed: u32 = 0; - for k in &a { - observed |= 1 << *k; - } - assert_eq!(observed, 0xFFFF_FFFF); -} - -#[test] -fn test_intersection() { - let mut a = LinkedHashSet::new(); - let mut b = LinkedHashSet::new(); - - assert!(a.insert(11)); - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(77)); - assert!(a.insert(103)); - assert!(a.insert(5)); - assert!(a.insert(-5)); - - assert!(b.insert(2)); - assert!(b.insert(11)); - assert!(b.insert(77)); - assert!(b.insert(-9)); - assert!(b.insert(-42)); - assert!(b.insert(5)); - assert!(b.insert(3)); - - let mut i = 0; - let expected = [3, 5, 11, 77]; - for x in a.intersection(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); -} - -#[test] -fn test_difference() { - let mut a = LinkedHashSet::new(); - let mut b = LinkedHashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(3)); - assert!(b.insert(9)); - - let mut i = 0; - let expected = [1, 5, 11]; - for x in a.difference(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); -} - -#[test] -fn test_symmetric_difference() { - let mut a = LinkedHashSet::new(); - let mut b = LinkedHashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(-2)); - assert!(b.insert(3)); - assert!(b.insert(9)); - assert!(b.insert(14)); - assert!(b.insert(22)); - - let mut i = 0; - let expected = [-2, 1, 5, 11, 14, 22]; - for x in a.symmetric_difference(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); -} - -#[test] -fn test_union() { - let mut a = LinkedHashSet::new(); - let mut b = LinkedHashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - assert!(a.insert(16)); - assert!(a.insert(19)); - assert!(a.insert(24)); - - assert!(b.insert(-2)); - assert!(b.insert(1)); - assert!(b.insert(5)); - assert!(b.insert(9)); - assert!(b.insert(13)); - assert!(b.insert(19)); - - let mut i = 0; - let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; - for x in a.union(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); -} - -#[test] -fn test_from_iter() { - let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - - let set: LinkedHashSet<_> = xs.iter().cloned().collect(); - - for x in &xs { - assert!(set.contains(x)); - } -} - -#[test] -fn test_move_iter() { - let hs = { - let mut hs = LinkedHashSet::new(); - - hs.insert('a'); - hs.insert('b'); - - hs - }; - - let v = hs.into_iter().collect::>(); - assert!(v == ['a', 'b'] || v == ['b', 'a']); -} - -#[test] -fn test_eq() { - let mut s1 = LinkedHashSet::new(); - - s1.insert(1); - s1.insert(2); - s1.insert(3); - - let mut s2 = LinkedHashSet::new(); - - s2.insert(1); - s2.insert(2); - - assert!(s1 != s2); - - s2.insert(3); - - assert_eq!(s1, s2); -} - -#[test] -fn test_show() { - let mut set = LinkedHashSet::new(); - let empty = LinkedHashSet::::new(); - - set.insert(1); - set.insert(2); - - let set_str = format!("{:?}", set); - - assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); - assert_eq!(format!("{:?}", empty), "{}"); -} - -#[test] -fn test_trivial_drain() { - let mut s = LinkedHashSet::::new(); - for _ in s.drain() {} - assert!(s.is_empty()); - drop(s); - - let mut s = LinkedHashSet::::new(); - drop(s.drain()); - assert!(s.is_empty()); -} - -#[test] -fn test_drain() { - let mut s: LinkedHashSet<_> = (1..100).collect(); - - for _ in 0..20 { - assert_eq!(s.len(), 99); - - { - let mut last_i = 0; - let mut d = s.drain(); - for (i, x) in d.by_ref().take(50).enumerate() { - last_i = i; - assert!(x != 0); - } - assert_eq!(last_i, 49); - } - - for _ in &s { - panic!("s should be empty!"); - } - - s.extend(1..100); - } -} - -#[test] -fn test_replace() { - use core::hash; - - #[derive(Debug)] - struct Foo(&'static str, i32); - - impl PartialEq for Foo { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl Eq for Foo {} - - impl hash::Hash for Foo { - fn hash(&self, h: &mut H) { - self.0.hash(h); - } - } - - let mut s = LinkedHashSet::new(); - assert_eq!(s.replace(Foo("a", 1)), None); - assert_eq!(s.len(), 1); - assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); - assert_eq!(s.len(), 1); - - let mut it = s.iter(); - assert_eq!(it.next(), Some(&Foo("a", 2))); - assert_eq!(it.next(), None); -} - -#[test] -fn test_extend_ref() { - let mut a = LinkedHashSet::new(); - a.insert(1); - - a.extend(&[2, 3, 4]); - - assert_eq!(a.len(), 4); - assert!(a.contains(&1)); - assert!(a.contains(&2)); - assert!(a.contains(&3)); - assert!(a.contains(&4)); - - let mut b = LinkedHashSet::new(); - b.insert(5); - b.insert(6); - - a.extend(&b); - - assert_eq!(a.len(), 6); - assert!(a.contains(&1)); - assert!(a.contains(&2)); - assert!(a.contains(&3)); - assert!(a.contains(&4)); - assert!(a.contains(&5)); - assert!(a.contains(&6)); -} - -#[test] -fn test_retain() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut set: LinkedHashSet = xs.iter().cloned().collect(); - set.retain(|&k| k % 2 == 0); - assert_eq!(set.len(), 3); - assert!(set.contains(&2)); - assert!(set.contains(&4)); - assert!(set.contains(&6)); -} - -#[test] -fn test_retain_with_order() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut set: LinkedHashSet = xs.iter().cloned().collect(); - let mut vec = Vec::new(); - set.retain_with_order(|&k| { - if k % 2 == 0 { - true - } else { - vec.push(k); - false - } - }); - assert_eq!(vec![1, 3, 5], vec); -} - -#[test] -fn insert_order() { - let mut set = LinkedHashSet::new(); - set.insert(1); - set.insert(2); - set.insert(3); - set.insert(4); - assert_eq!( - set.clone().into_iter().collect::>(), - vec![1, 2, 3, 4] - ); - assert_eq!(set.into_iter().collect::>(), vec![1, 2, 3, 4]); -} - -#[test] -fn front_back() { - let mut set = LinkedHashSet::new(); - set.insert(1); - set.insert(2); - set.insert(3); - set.insert(4); - assert_eq!(set.front(), Some(&1)); - assert_eq!(set.back(), Some(&4)); - assert_eq!(set.pop_back(), Some(4)); - assert_eq!(set.back(), Some(&3)); - assert_eq!(set.pop_front(), Some(1)); - assert_eq!(set.front(), Some(&2)); -} - -#[test] -fn double_ended_iter() { - let mut set = LinkedHashSet::new(); - set.insert(1); - set.insert(2); - set.insert(3); - set.insert(4); - - let mut iter = set.iter(); - assert_eq!(iter.next(), Some(&1)); - assert_eq!(iter.next(), Some(&2)); - assert_eq!(iter.next_back(), Some(&4)); - assert_eq!(iter.next_back(), Some(&3)); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - drop(iter); - - let mut iter = set.drain(); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next_back(), Some(4)); - assert_eq!(iter.next_back(), Some(3)); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); - drop(iter); - - set.insert(1); - set.insert(2); - set.insert(3); - set.insert(4); - - let mut iter = set.into_iter(); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next_back(), Some(4)); - assert_eq!(iter.next_back(), Some(3)); - assert_eq!(iter.next_back(), None); - assert_eq!(iter.next(), None); - assert_eq!(iter.next_back(), None); -} - -#[test] -fn to_back_front_order() { - let mut set = LinkedHashSet::new(); - set.insert(1); - set.insert(2); - set.insert(3); - set.insert(4); - - assert_eq!(set.back().copied(), Some(4)); - assert_eq!(set.front().copied(), Some(1)); - set.to_back(&2); - assert_eq!(set.back().copied(), Some(2)); - set.to_front(&3); - assert_eq!(set.front().copied(), Some(3)); -} - -#[test] -fn test_order_equality() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut set1: LinkedHashSet = xs.iter().copied().collect(); - let mut set2: LinkedHashSet = xs.iter().copied().collect(); - - assert_eq!(set1, set2); - - set1.to_front(&4); - assert_ne!(set1, set2); - - set2.to_front(&4); - assert_eq!(set1, set2); -} diff --git a/third-party/vendor/hashlink/tests/lru_cache.rs b/third-party/vendor/hashlink/tests/lru_cache.rs deleted file mode 100644 index f863c70e..00000000 --- a/third-party/vendor/hashlink/tests/lru_cache.rs +++ /dev/null @@ -1,166 +0,0 @@ -use hashlink::LruCache; - -#[test] -fn test_put_and_get() { - let mut cache = LruCache::new(2); - cache.insert(1, 10); - cache.insert(2, 20); - assert_eq!(cache.get_mut(&1), Some(&mut 10)); - assert_eq!(cache.get_mut(&2), Some(&mut 20)); - assert_eq!(cache.len(), 2); -} - -#[test] -fn test_put_update() { - let mut cache = LruCache::new(1); - cache.insert("1", 10); - cache.insert("1", 19); - assert_eq!(cache.get_mut("1"), Some(&mut 19)); - assert_eq!(cache.len(), 1); -} - -#[test] -fn test_contains_key() { - let mut cache = LruCache::new(1); - cache.insert("1", 10); - assert_eq!(cache.contains_key("1"), true); -} - -#[test] -fn test_expire_lru() { - let mut cache = LruCache::new(2); - cache.insert("foo1", "bar1"); - cache.insert("foo2", "bar2"); - cache.insert("foo3", "bar3"); - assert!(cache.get_mut("foo1").is_none()); - cache.insert("foo2", "bar2update"); - cache.insert("foo4", "bar4"); - assert!(cache.get_mut("foo3").is_none()); -} - -#[test] -fn test_pop() { - let mut cache = LruCache::new(2); - cache.insert(1, 10); - cache.insert(2, 20); - assert_eq!(cache.len(), 2); - let opt1 = cache.remove(&1); - assert!(opt1.is_some()); - assert_eq!(opt1.unwrap(), 10); - assert!(cache.get_mut(&1).is_none()); - assert_eq!(cache.len(), 1); -} - -#[test] -fn test_change_capacity() { - let mut cache = LruCache::new(2); - assert_eq!(cache.capacity(), 2); - cache.insert(1, 10); - cache.insert(2, 20); - cache.set_capacity(1); - assert!(cache.get_mut(&1).is_none()); - assert_eq!(cache.capacity(), 1); -} - -#[test] -fn test_remove() { - let mut cache = LruCache::new(3); - cache.insert(1, 10); - cache.insert(2, 20); - cache.insert(3, 30); - cache.insert(4, 40); - cache.insert(5, 50); - cache.remove(&3); - cache.remove(&4); - assert!(cache.get_mut(&3).is_none()); - assert!(cache.get_mut(&4).is_none()); - cache.insert(6, 60); - cache.insert(7, 70); - cache.insert(8, 80); - assert!(cache.get_mut(&5).is_none()); - assert_eq!(cache.get_mut(&6), Some(&mut 60)); - assert_eq!(cache.get_mut(&7), Some(&mut 70)); - assert_eq!(cache.get_mut(&8), Some(&mut 80)); -} - -#[test] -fn test_clear() { - let mut cache = LruCache::new(2); - cache.insert(1, 10); - cache.insert(2, 20); - cache.clear(); - assert!(cache.get_mut(&1).is_none()); - assert!(cache.get_mut(&2).is_none()); - assert!(cache.is_empty()) -} - -#[test] -fn test_iter() { - let mut cache = LruCache::new(3); - cache.insert(1, 10); - cache.insert(2, 20); - cache.insert(3, 30); - cache.insert(4, 40); - cache.insert(5, 50); - assert_eq!( - cache.iter().collect::>(), - [(&3, &30), (&4, &40), (&5, &50)] - ); - assert_eq!( - cache.iter_mut().collect::>(), - [(&3, &mut 30), (&4, &mut 40), (&5, &mut 50)] - ); - assert_eq!( - cache.iter().rev().collect::>(), - [(&5, &50), (&4, &40), (&3, &30)] - ); - assert_eq!( - cache.iter_mut().rev().collect::>(), - [(&5, &mut 50), (&4, &mut 40), (&3, &mut 30)] - ); -} - -#[test] -fn test_peek() { - let mut cache = LruCache::new_unbounded(); - cache.insert(1, 10); - cache.insert(2, 20); - cache.insert(3, 30); - cache.insert(4, 40); - cache.insert(5, 50); - cache.insert(6, 60); - - assert_eq!(cache.remove_lru(), Some((1, 10))); - assert_eq!(cache.peek(&2), Some(&20)); - assert_eq!(cache.remove_lru(), Some((2, 20))); - assert_eq!(cache.peek_mut(&3), Some(&mut 30)); - assert_eq!(cache.remove_lru(), Some((3, 30))); - assert_eq!(cache.get(&4), Some(&40)); - assert_eq!(cache.remove_lru(), Some((5, 50))); -} - -#[test] -fn test_entry() { - let mut cache = LruCache::new(4); - - cache.insert(1, 10); - cache.insert(2, 20); - cache.insert(3, 30); - cache.insert(4, 40); - cache.insert(5, 50); - cache.insert(6, 60); - - assert_eq!(cache.len(), 4); - - cache.entry(7).or_insert(70); - cache.entry(8).or_insert(80); - cache.entry(9).or_insert(90); - - assert!(cache.len() <= 5); - - cache.raw_entry_mut().from_key(&10).or_insert(10, 100); - cache.raw_entry_mut().from_key(&11).or_insert(11, 110); - cache.raw_entry_mut().from_key(&12).or_insert(12, 120); - - assert!(cache.len() <= 5); -} diff --git a/third-party/vendor/hashlink/tests/serde.rs b/third-party/vendor/hashlink/tests/serde.rs deleted file mode 100644 index 2cf4a3e3..00000000 --- a/third-party/vendor/hashlink/tests/serde.rs +++ /dev/null @@ -1,110 +0,0 @@ -#![cfg(feature = "serde_impl")] - -use std::hash::BuildHasherDefault; - -use hashlink::{LinkedHashMap, LinkedHashSet}; -use rustc_hash::FxHasher; -use serde_test::{assert_tokens, Token}; - -#[test] -fn map_serde_tokens_empty() { - let map = LinkedHashMap::::new(); - - assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); -} - -#[test] -fn map_serde_tokens() { - let mut map = LinkedHashMap::new(); - map.insert('a', 10); - map.insert('b', 20); - map.insert('c', 30); - - assert_tokens( - &map, - &[ - Token::Map { len: Some(3) }, - Token::Char('a'), - Token::I32(10), - Token::Char('b'), - Token::I32(20), - Token::Char('c'), - Token::I32(30), - Token::MapEnd, - ], - ); -} - -#[test] -fn map_serde_tokens_empty_generic() { - let map = LinkedHashMap::>::default(); - - assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); -} - -#[test] -fn map_serde_tokens_generic() { - let mut map = LinkedHashMap::>::default(); - map.insert('a', 10); - map.insert('b', 20); - map.insert('c', 30); - - assert_tokens( - &map, - &[ - Token::Map { len: Some(3) }, - Token::Char('a'), - Token::I32(10), - Token::Char('b'), - Token::I32(20), - Token::Char('c'), - Token::I32(30), - Token::MapEnd, - ], - ); -} - -#[test] -fn set_serde_tokens_empty() { - let set = LinkedHashSet::::new(); - - assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); -} - -#[test] -fn set_serde_tokens() { - let mut set = LinkedHashSet::new(); - set.insert(10); - set.insert(20); - set.insert(30); - - assert_tokens( - &set, - &[ - Token::Seq { len: Some(3) }, - Token::I32(10), - Token::I32(20), - Token::I32(30), - Token::SeqEnd, - ], - ); -} - -#[test] -fn set_serde_tokens_generic() { - let mut set = LinkedHashSet::>::default(); - set.insert('a'); - set.insert('b'); - set.insert('c'); - - assert_tokens( - &set, - &[ - Token::Seq { len: Some(3) }, - Token::Char('a'), - Token::Char('b'), - Token::Char('c'), - Token::SeqEnd, - ], - ); -} diff --git a/third-party/vendor/heck/.cargo-checksum.json b/third-party/vendor/heck/.cargo-checksum.json deleted file mode 100644 index ffff4c9c..00000000 --- a/third-party/vendor/heck/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"be2b711f318b4447b7c0fa067ac1804dff0b01894d2782722646910a6b2c4b10","Cargo.toml":"bef2e967708cafccb70a6de0f2eeed8914f9a58c1fc9094cf0e6bde671768f7b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"a53c56a404fa7b97e4a5426798430186e715fcf38480327d42700494cae70f76","src/kebab.rs":"f2a4900541fe36584b0705108f5f1d23501bcb3429fffe04106077baecc6dc5a","src/lib.rs":"6cf5759deb604eb1035061ed52c1f71a629ac3fa6faefecceeb9d3cb9f4a9919","src/lower_camel.rs":"24a3ea7ce7f765b27fb0adec207498569f27045edc56c9089ae05fc428c54d5f","src/shouty_kebab.rs":"4516fbb2295c400869221912257828c90e7c0d43f3bdf4aaefb6d384606f4866","src/shouty_snake.rs":"01b8c1e7ac5e680827e2744e62bf4704fc7ebd0d555c5b040bca5f5fb50e4ffd","src/snake.rs":"fc69443dd1a9248667484d5feb52911a1c6dfed1442b01b5b23e371c5b716a5e","src/title.rs":"0cc0b3014559ab6047ed9e7afb624bbe97014a4498297a4c3b28f3410b75d1dc","src/train.rs":"6d20c7153b2e574653c57d039a5077c707c4f15e5b8be765bd5042a4dabc32d4","src/upper_camel.rs":"9cb094ade94cf6212a4b6e491b0fdad92ad8fbb0d55095c70691f9d66ce25366"},"package":"95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"} \ No newline at end of file diff --git a/third-party/vendor/heck/CHANGELOG.md b/third-party/vendor/heck/CHANGELOG.md deleted file mode 100644 index c0f2f24d..00000000 --- a/third-party/vendor/heck/CHANGELOG.md +++ /dev/null @@ -1,17 +0,0 @@ -# 0.4.1 - -Improvements: - -- Add Train-Case support - -# 0.4.0 - -Breaking changes: - -* Make unicode support optional (off by default). Enable the `unicode` crate - feature if you need unicode support. -* Rename all traits from `SomeCase` to `ToSomeCase`, matching `std`s convention - of beginning trait names with a verb (`ToOwned`, `AsRef`, …) -* Rename `ToMixedCase` to `ToLowerCamelCase` -* Rename `ToCamelCase` to `ToUpperCamelCase` -* Add `ToPascalCase` as an alias to `ToUpperCamelCase` diff --git a/third-party/vendor/heck/Cargo.toml b/third-party/vendor/heck/Cargo.toml deleted file mode 100644 index 79903686..00000000 --- a/third-party/vendor/heck/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2018" -name = "heck" -version = "0.4.1" -authors = ["Without Boats "] -include = [ - "src/**/*", - "LICENSE-*", - "README.md", - "CHANGELOG.md", -] -description = "heck is a case conversion library." -homepage = "https://github.com/withoutboats/heck" -documentation = "https://docs.rs/heck" -readme = "README.md" -keywords = [ - "string", - "case", - "camel", - "snake", - "unicode", -] -license = "MIT OR Apache-2.0" -repository = "https://github.com/withoutboats/heck" - -[dependencies.unicode-segmentation] -version = "1.2.0" -optional = true - -[features] -default = [] -unicode = ["unicode-segmentation"] diff --git a/third-party/vendor/heck/LICENSE-APACHE b/third-party/vendor/heck/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/third-party/vendor/heck/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - 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/third-party/vendor/heck/LICENSE-MIT b/third-party/vendor/heck/LICENSE-MIT deleted file mode 100644 index e69282e3..00000000 --- a/third-party/vendor/heck/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2015 The Rust Project Developers - -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/third-party/vendor/heck/README.md b/third-party/vendor/heck/README.md deleted file mode 100644 index 5e052e75..00000000 --- a/third-party/vendor/heck/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# **heck** is a case conversion library - -!["I specifically requested the opposite of this."](./no_step_on_snek.png) - -This library exists to provide case conversion between common cases like -CamelCase and snake_case. It is intended to be unicode aware, internally -consistent, and reasonably well performing. - -## Definition of a word boundary - -Word boundaries are defined as the "unicode words" defined in the -`unicode_segmentation` library, as well as within those words in this manner: - -1. All underscore characters are considered word boundaries. -2. If an uppercase character is followed by lowercase letters, a word boundary -is considered to be just prior to that uppercase character. -3. If multiple uppercase characters are consecutive, they are considered to be -within a single word, except that the last will be part of the next word if it -is followed by lowercase characters (see rule 2). - -That is, "HelloWorld" is segmented `Hello|World` whereas "XMLHttpRequest" is -segmented `XML|Http|Request`. - -Characters not within words (such as spaces, punctuations, and underscores) -are not included in the output string except as they are a part of the case -being converted to. Multiple adjacent word boundaries (such as a series of -underscores) are folded into one. ("hello__world" in snake case is therefore -"hello_world", not the exact same string). Leading or trailing word boundary -indicators are dropped, except insofar as CamelCase capitalizes the first word. - -## Cases contained in this library: - -1. UpperCamelCase -2. lowerCamelCase -3. snake_case -4. kebab-case -5. SHOUTY_SNAKE_CASE -6. Title Case -7. SHOUTY-KEBAB-CASE -8. Train-Case - -## Contributing - -PRs of additional well-established cases welcome. - -This library is a little bit opinionated (dropping punctuation, for example). -If that doesn't fit your use case, I hope there is another crate that does. I -would prefer **not** to receive PRs to make this behavior more configurable. - -Bug reports & fixes always welcome. :-) - -## MSRV - -The minimum supported Rust version for this crate is 1.32.0. This may change in -minor or patch releases, but we probably won't ever require a very recent -version. If you would like to have a stronger guarantee than that, please open -an issue. - -## License - -heck is distributed under the terms of both the MIT license and the -Apache License (Version 2.0). - -See LICENSE-APACHE and LICENSE-MIT for details. diff --git a/third-party/vendor/heck/src/kebab.rs b/third-party/vendor/heck/src/kebab.rs deleted file mode 100644 index 6cce5a56..00000000 --- a/third-party/vendor/heck/src/kebab.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::fmt; - -use crate::{lowercase, transform}; - -/// This trait defines a kebab case conversion. -/// -/// In kebab-case, word boundaries are indicated by hyphens. -/// -/// ## Example: -/// -/// ```rust -/// use heck::ToKebabCase; -/// -/// let sentence = "We are going to inherit the earth."; -/// assert_eq!(sentence.to_kebab_case(), "we-are-going-to-inherit-the-earth"); -/// ``` -pub trait ToKebabCase: ToOwned { - /// Convert this type to kebab case. - fn to_kebab_case(&self) -> Self::Owned; -} - -impl ToKebabCase for str { - fn to_kebab_case(&self) -> Self::Owned { - AsKebabCase(self).to_string() - } -} - -/// This wrapper performs a kebab case conversion in [`fmt::Display`]. -/// -/// ## Example: -/// -/// ``` -/// use heck::AsKebabCase; -/// -/// let sentence = "We are going to inherit the earth."; -/// assert_eq!(format!("{}", AsKebabCase(sentence)), "we-are-going-to-inherit-the-earth"); -/// ``` -pub struct AsKebabCase>(pub T); - -impl> fmt::Display for AsKebabCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - transform(self.0.as_ref(), lowercase, |f| write!(f, "-"), f) - } -} - -#[cfg(test)] -mod tests { - use super::ToKebabCase; - - macro_rules! t { - ($t:ident : $s1:expr => $s2:expr) => { - #[test] - fn $t() { - assert_eq!($s1.to_kebab_case(), $s2) - } - }; - } - - t!(test1: "CamelCase" => "camel-case"); - t!(test2: "This is Human case." => "this-is-human-case"); - t!(test3: "MixedUP CamelCase, with some Spaces" => "mixed-up-camel-case-with-some-spaces"); - t!(test4: "mixed_up_ snake_case with some _spaces" => "mixed-up-snake-case-with-some-spaces"); - t!(test5: "kebab-case" => "kebab-case"); - t!(test6: "SHOUTY_SNAKE_CASE" => "shouty-snake-case"); - t!(test7: "snake_case" => "snake-case"); - t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "this-contains-all-kinds-of-word-boundaries"); - #[cfg(feature = "unicode")] - t!(test9: "XΣXΣ baffle" => "xσxς-baffle"); - t!(test10: "XMLHttpRequest" => "xml-http-request"); -} diff --git a/third-party/vendor/heck/src/lib.rs b/third-party/vendor/heck/src/lib.rs deleted file mode 100644 index 49bfb0ef..00000000 --- a/third-party/vendor/heck/src/lib.rs +++ /dev/null @@ -1,209 +0,0 @@ -//! **heck** is a case conversion library. -//! -//! This library exists to provide case conversion between common cases like -//! CamelCase and snake_case. It is intended to be unicode aware, internally -//! consistent, and reasonably well performing. -//! -//! ## Definition of a word boundary -//! -//! Word boundaries are defined as the "unicode words" defined in the -//! `unicode_segmentation` library, as well as within those words in this -//! manner: -//! -//! 1. All underscore characters are considered word boundaries. -//! 2. If an uppercase character is followed by lowercase letters, a word -//! boundary is considered to be just prior to that uppercase character. -//! 3. If multiple uppercase characters are consecutive, they are considered to -//! be within a single word, except that the last will be part of the next word -//! if it is followed by lowercase characters (see rule 2). -//! -//! That is, "HelloWorld" is segmented `Hello|World` whereas "XMLHttpRequest" is -//! segmented `XML|Http|Request`. -//! -//! Characters not within words (such as spaces, punctuations, and underscores) -//! are not included in the output string except as they are a part of the case -//! being converted to. Multiple adjacent word boundaries (such as a series of -//! underscores) are folded into one. ("hello__world" in snake case is therefore -//! "hello_world", not the exact same string). Leading or trailing word boundary -//! indicators are dropped, except insofar as CamelCase capitalizes the first -//! word. -//! -//! ### Cases contained in this library: -//! -//! 1. UpperCamelCase -//! 2. lowerCamelCase -//! 3. snake_case -//! 4. kebab-case -//! 5. SHOUTY_SNAKE_CASE -//! 6. Title Case -//! 7. SHOUTY-KEBAB-CASE -//! 8. Train-Case -#![deny(missing_docs)] -#![forbid(unsafe_code)] - -mod kebab; -mod lower_camel; -mod shouty_kebab; -mod shouty_snake; -mod snake; -mod title; -mod train; -mod upper_camel; - -pub use kebab::{AsKebabCase, ToKebabCase}; -pub use lower_camel::{AsLowerCamelCase, ToLowerCamelCase}; -pub use shouty_kebab::{AsShoutyKebabCase, ToShoutyKebabCase}; -pub use shouty_snake::{ - AsShoutySnakeCase, AsShoutySnakeCase as AsShoutySnekCase, ToShoutySnakeCase, ToShoutySnekCase, -}; -pub use snake::{AsSnakeCase, AsSnakeCase as AsSnekCase, ToSnakeCase, ToSnekCase}; -pub use title::{AsTitleCase, ToTitleCase}; -pub use train::{AsTrainCase, ToTrainCase}; -pub use upper_camel::{ - AsUpperCamelCase, AsUpperCamelCase as AsPascalCase, ToPascalCase, ToUpperCamelCase, -}; - -use std::fmt; - -#[cfg(feature = "unicode")] -fn get_iterator(s: &str) -> unicode_segmentation::UnicodeWords { - use unicode_segmentation::UnicodeSegmentation; - s.unicode_words() -} -#[cfg(not(feature = "unicode"))] -fn get_iterator(s: &str) -> impl Iterator { - s.split(|letter: char| !letter.is_ascii_alphanumeric()) -} - -fn transform( - s: &str, - mut with_word: F, - mut boundary: G, - f: &mut fmt::Formatter, -) -> fmt::Result -where - F: FnMut(&str, &mut fmt::Formatter) -> fmt::Result, - G: FnMut(&mut fmt::Formatter) -> fmt::Result, -{ - /// Tracks the current 'mode' of the transformation algorithm as it scans - /// the input string. - /// - /// The mode is a tri-state which tracks the case of the last cased - /// character of the current word. If there is no cased character - /// (either lowercase or uppercase) since the previous word boundary, - /// than the mode is `Boundary`. If the last cased character is lowercase, - /// then the mode is `Lowercase`. Othertherwise, the mode is - /// `Uppercase`. - #[derive(Clone, Copy, PartialEq)] - enum WordMode { - /// There have been no lowercase or uppercase characters in the current - /// word. - Boundary, - /// The previous cased character in the current word is lowercase. - Lowercase, - /// The previous cased character in the current word is uppercase. - Uppercase, - } - - let mut first_word = true; - - for word in get_iterator(s) { - let mut char_indices = word.char_indices().peekable(); - let mut init = 0; - let mut mode = WordMode::Boundary; - - while let Some((i, c)) = char_indices.next() { - // Skip underscore characters - if c == '_' { - if init == i { - init += 1; - } - continue; - } - - if let Some(&(next_i, next)) = char_indices.peek() { - // The mode including the current character, assuming the - // current character does not result in a word boundary. - let next_mode = if c.is_lowercase() { - WordMode::Lowercase - } else if c.is_uppercase() { - WordMode::Uppercase - } else { - mode - }; - - // Word boundary after if next is underscore or current is - // not uppercase and next is uppercase - if next == '_' || (next_mode == WordMode::Lowercase && next.is_uppercase()) { - if !first_word { - boundary(f)?; - } - with_word(&word[init..next_i], f)?; - first_word = false; - init = next_i; - mode = WordMode::Boundary; - - // Otherwise if current and previous are uppercase and next - // is lowercase, word boundary before - } else if mode == WordMode::Uppercase && c.is_uppercase() && next.is_lowercase() { - if !first_word { - boundary(f)?; - } else { - first_word = false; - } - with_word(&word[init..i], f)?; - init = i; - mode = WordMode::Boundary; - - // Otherwise no word boundary, just update the mode - } else { - mode = next_mode; - } - } else { - // Collect trailing characters as a word - if !first_word { - boundary(f)?; - } else { - first_word = false; - } - with_word(&word[init..], f)?; - break; - } - } - } - - Ok(()) -} - -fn lowercase(s: &str, f: &mut fmt::Formatter) -> fmt::Result { - let mut chars = s.chars().peekable(); - while let Some(c) = chars.next() { - if c == 'Σ' && chars.peek().is_none() { - write!(f, "ς")?; - } else { - write!(f, "{}", c.to_lowercase())?; - } - } - - Ok(()) -} - -fn uppercase(s: &str, f: &mut fmt::Formatter) -> fmt::Result { - for c in s.chars() { - write!(f, "{}", c.to_uppercase())?; - } - - Ok(()) -} - -fn capitalize(s: &str, f: &mut fmt::Formatter) -> fmt::Result { - let mut char_indices = s.char_indices(); - if let Some((_, c)) = char_indices.next() { - write!(f, "{}", c.to_uppercase())?; - if let Some((i, _)) = char_indices.next() { - lowercase(&s[i..], f)?; - } - } - - Ok(()) -} diff --git a/third-party/vendor/heck/src/lower_camel.rs b/third-party/vendor/heck/src/lower_camel.rs deleted file mode 100644 index f1d6c94c..00000000 --- a/third-party/vendor/heck/src/lower_camel.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::fmt; - -use crate::{capitalize, lowercase, transform}; - -/// This trait defines a lower camel case conversion. -/// -/// In lowerCamelCase, word boundaries are indicated by capital letters, -/// excepting the first word. -/// -/// ## Example: -/// -/// ```rust -/// use heck::ToLowerCamelCase; -/// -/// let sentence = "It is we who built these palaces and cities."; -/// assert_eq!(sentence.to_lower_camel_case(), "itIsWeWhoBuiltThesePalacesAndCities"); -/// ``` -pub trait ToLowerCamelCase: ToOwned { - /// Convert this type to lower camel case. - fn to_lower_camel_case(&self) -> Self::Owned; -} - -impl ToLowerCamelCase for str { - fn to_lower_camel_case(&self) -> String { - AsLowerCamelCase(self).to_string() - } -} - -/// This wrapper performs a lower camel case conversion in [`fmt::Display`]. -/// -/// ## Example: -/// -/// ``` -/// use heck::AsLowerCamelCase; -/// -/// let sentence = "It is we who built these palaces and cities."; -/// assert_eq!(format!("{}", AsLowerCamelCase(sentence)), "itIsWeWhoBuiltThesePalacesAndCities"); -/// ``` -pub struct AsLowerCamelCase>(pub T); - -impl> fmt::Display for AsLowerCamelCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut first = true; - transform( - self.0.as_ref(), - |s, f| { - if first { - first = false; - lowercase(s, f) - } else { - capitalize(s, f) - } - }, - |_| Ok(()), - f, - ) - } -} - -#[cfg(test)] -mod tests { - use super::ToLowerCamelCase; - - macro_rules! t { - ($t:ident : $s1:expr => $s2:expr) => { - #[test] - fn $t() { - assert_eq!($s1.to_lower_camel_case(), $s2) - } - }; - } - - t!(test1: "CamelCase" => "camelCase"); - t!(test2: "This is Human case." => "thisIsHumanCase"); - t!(test3: "MixedUP CamelCase, with some Spaces" => "mixedUpCamelCaseWithSomeSpaces"); - t!(test4: "mixed_up_ snake_case, with some _spaces" => "mixedUpSnakeCaseWithSomeSpaces"); - t!(test5: "kebab-case" => "kebabCase"); - t!(test6: "SHOUTY_SNAKE_CASE" => "shoutySnakeCase"); - t!(test7: "snake_case" => "snakeCase"); - t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "thisContainsAllKindsOfWordBoundaries"); - #[cfg(feature = "unicode")] - t!(test9: "XΣXΣ baffle" => "xσxςBaffle"); - t!(test10: "XMLHttpRequest" => "xmlHttpRequest"); - // TODO unicode tests -} diff --git a/third-party/vendor/heck/src/shouty_kebab.rs b/third-party/vendor/heck/src/shouty_kebab.rs deleted file mode 100644 index e679978b..00000000 --- a/third-party/vendor/heck/src/shouty_kebab.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::fmt; - -use crate::{transform, uppercase}; - -/// This trait defines a shouty kebab case conversion. -/// -/// In SHOUTY-KEBAB-CASE, word boundaries are indicated by hyphens and all -/// words are in uppercase. -/// -/// ## Example: -/// -/// ```rust -/// use heck::ToShoutyKebabCase; -/// -/// let sentence = "We are going to inherit the earth."; -/// assert_eq!(sentence.to_shouty_kebab_case(), "WE-ARE-GOING-TO-INHERIT-THE-EARTH"); -/// ``` -pub trait ToShoutyKebabCase: ToOwned { - /// Convert this type to shouty kebab case. - fn to_shouty_kebab_case(&self) -> Self::Owned; -} - -impl ToShoutyKebabCase for str { - fn to_shouty_kebab_case(&self) -> Self::Owned { - AsShoutyKebabCase(self).to_string() - } -} - -/// This wrapper performs a kebab case conversion in [`fmt::Display`]. -/// -/// ## Example: -/// -/// ``` -/// use heck::AsShoutyKebabCase; -/// -/// let sentence = "We are going to inherit the earth."; -/// assert_eq!(format!("{}", AsShoutyKebabCase(sentence)), "WE-ARE-GOING-TO-INHERIT-THE-EARTH"); -/// ``` -pub struct AsShoutyKebabCase>(pub T); - -impl> fmt::Display for AsShoutyKebabCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - transform(self.0.as_ref(), uppercase, |f| write!(f, "-"), f) - } -} - -#[cfg(test)] -mod tests { - use super::ToShoutyKebabCase; - - macro_rules! t { - ($t:ident : $s1:expr => $s2:expr) => { - #[test] - fn $t() { - assert_eq!($s1.to_shouty_kebab_case(), $s2) - } - }; - } - - t!(test1: "CamelCase" => "CAMEL-CASE"); - t!(test2: "This is Human case." => "THIS-IS-HUMAN-CASE"); - t!(test3: "MixedUP CamelCase, with some Spaces" => "MIXED-UP-CAMEL-CASE-WITH-SOME-SPACES"); - t!(test4: "mixed_up_ snake_case with some _spaces" => "MIXED-UP-SNAKE-CASE-WITH-SOME-SPACES"); - t!(test5: "kebab-case" => "KEBAB-CASE"); - t!(test6: "SHOUTY_SNAKE_CASE" => "SHOUTY-SNAKE-CASE"); - t!(test7: "snake_case" => "SNAKE-CASE"); - t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "THIS-CONTAINS-ALL-KINDS-OF-WORD-BOUNDARIES"); - #[cfg(feature = "unicode")] - t!(test9: "XΣXΣ baffle" => "XΣXΣ-BAFFLE"); - t!(test10: "XMLHttpRequest" => "XML-HTTP-REQUEST"); - t!(test11: "SHOUTY-KEBAB-CASE" => "SHOUTY-KEBAB-CASE"); -} diff --git a/third-party/vendor/heck/src/shouty_snake.rs b/third-party/vendor/heck/src/shouty_snake.rs deleted file mode 100644 index d5043755..00000000 --- a/third-party/vendor/heck/src/shouty_snake.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::fmt; - -use crate::{transform, uppercase}; - -/// This trait defines a shouty snake case conversion. -/// -/// In SHOUTY_SNAKE_CASE, word boundaries are indicated by underscores and all -/// words are in uppercase. -/// -/// ## Example: -/// -/// ```rust -/// use heck::ToShoutySnakeCase; -/// -/// let sentence = "That world is growing in this minute."; -/// assert_eq!(sentence.to_shouty_snake_case(), "THAT_WORLD_IS_GROWING_IN_THIS_MINUTE"); -/// ``` -pub trait ToShoutySnakeCase: ToOwned { - /// Convert this type to shouty snake case. - fn to_shouty_snake_case(&self) -> Self::Owned; -} - -/// Oh heck, ToShoutySnekCase is an alias for ToShoutySnakeCase. See -/// ToShoutySnakeCase for more documentation. -pub trait ToShoutySnekCase: ToOwned { - /// CONVERT THIS TYPE TO SNEK CASE. - #[allow(non_snake_case)] - fn TO_SHOUTY_SNEK_CASE(&self) -> Self::Owned; -} - -impl ToShoutySnekCase for T { - fn TO_SHOUTY_SNEK_CASE(&self) -> Self::Owned { - self.to_shouty_snake_case() - } -} - -impl ToShoutySnakeCase for str { - fn to_shouty_snake_case(&self) -> Self::Owned { - AsShoutySnakeCase(self).to_string() - } -} - -/// This wrapper performs a shouty snake case conversion in [`fmt::Display`]. -/// -/// ## Example: -/// -/// ``` -/// use heck::AsShoutySnakeCase; -/// -/// let sentence = "That world is growing in this minute."; -/// assert_eq!(format!("{}", AsShoutySnakeCase(sentence)), "THAT_WORLD_IS_GROWING_IN_THIS_MINUTE"); -/// ``` -pub struct AsShoutySnakeCase>(pub T); - -impl> fmt::Display for AsShoutySnakeCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - transform(self.0.as_ref(), uppercase, |f| write!(f, "_"), f) - } -} - -#[cfg(test)] -mod tests { - use super::ToShoutySnakeCase; - - macro_rules! t { - ($t:ident : $s1:expr => $s2:expr) => { - #[test] - fn $t() { - assert_eq!($s1.to_shouty_snake_case(), $s2) - } - }; - } - - t!(test1: "CamelCase" => "CAMEL_CASE"); - t!(test2: "This is Human case." => "THIS_IS_HUMAN_CASE"); - t!(test3: "MixedUP CamelCase, with some Spaces" => "MIXED_UP_CAMEL_CASE_WITH_SOME_SPACES"); - t!(test4: "mixed_up_snake_case with some _spaces" => "MIXED_UP_SNAKE_CASE_WITH_SOME_SPACES"); - t!(test5: "kebab-case" => "KEBAB_CASE"); - t!(test6: "SHOUTY_SNAKE_CASE" => "SHOUTY_SNAKE_CASE"); - t!(test7: "snake_case" => "SNAKE_CASE"); - t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "THIS_CONTAINS_ALL_KINDS_OF_WORD_BOUNDARIES"); - #[cfg(feature = "unicode")] - t!(test9: "XΣXΣ baffle" => "XΣXΣ_BAFFLE"); - t!(test10: "XMLHttpRequest" => "XML_HTTP_REQUEST"); -} diff --git a/third-party/vendor/heck/src/snake.rs b/third-party/vendor/heck/src/snake.rs deleted file mode 100644 index 127a8642..00000000 --- a/third-party/vendor/heck/src/snake.rs +++ /dev/null @@ -1,98 +0,0 @@ -use std::fmt; - -use crate::{lowercase, transform}; - -/// This trait defines a snake case conversion. -/// -/// In snake_case, word boundaries are indicated by underscores. -/// -/// ## Example: -/// -/// ```rust -/// use heck::ToSnakeCase; -/// -/// let sentence = "We carry a new world here, in our hearts."; -/// assert_eq!(sentence.to_snake_case(), "we_carry_a_new_world_here_in_our_hearts"); -/// ``` -pub trait ToSnakeCase: ToOwned { - /// Convert this type to snake case. - fn to_snake_case(&self) -> Self::Owned; -} - -/// Oh heck, SnekCase is an alias for ToSnakeCase. See ToSnakeCase for -/// more documentation. -pub trait ToSnekCase: ToOwned { - /// Convert this type to snek case. - fn to_snek_case(&self) -> Self::Owned; -} - -impl ToSnekCase for T { - fn to_snek_case(&self) -> Self::Owned { - self.to_snake_case() - } -} - -impl ToSnakeCase for str { - fn to_snake_case(&self) -> String { - AsSnakeCase(self).to_string() - } -} - -/// This wrapper performs a snake case conversion in [`fmt::Display`]. -/// -/// ## Example: -/// -/// ``` -/// use heck::AsSnakeCase; -/// -/// let sentence = "We carry a new world here, in our hearts."; -/// assert_eq!(format!("{}", AsSnakeCase(sentence)), "we_carry_a_new_world_here_in_our_hearts"); -/// ``` -pub struct AsSnakeCase>(pub T); - -impl> fmt::Display for AsSnakeCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - transform(self.0.as_ref(), lowercase, |f| write!(f, "_"), f) - } -} - -#[cfg(test)] -mod tests { - use super::ToSnakeCase; - - macro_rules! t { - ($t:ident : $s1:expr => $s2:expr) => { - #[test] - fn $t() { - assert_eq!($s1.to_snake_case(), $s2) - } - }; - } - - t!(test1: "CamelCase" => "camel_case"); - t!(test2: "This is Human case." => "this_is_human_case"); - t!(test3: "MixedUP CamelCase, with some Spaces" => "mixed_up_camel_case_with_some_spaces"); - t!(test4: "mixed_up_ snake_case with some _spaces" => "mixed_up_snake_case_with_some_spaces"); - t!(test5: "kebab-case" => "kebab_case"); - t!(test6: "SHOUTY_SNAKE_CASE" => "shouty_snake_case"); - t!(test7: "snake_case" => "snake_case"); - t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "this_contains_all_kinds_of_word_boundaries"); - #[cfg(feature = "unicode")] - t!(test9: "XΣXΣ baffle" => "xσxς_baffle"); - t!(test10: "XMLHttpRequest" => "xml_http_request"); - t!(test11: "FIELD_NAME11" => "field_name11"); - t!(test12: "99BOTTLES" => "99bottles"); - t!(test13: "FieldNamE11" => "field_nam_e11"); - - t!(test14: "abc123def456" => "abc123def456"); - t!(test16: "abc123DEF456" => "abc123_def456"); - t!(test17: "abc123Def456" => "abc123_def456"); - t!(test18: "abc123DEf456" => "abc123_d_ef456"); - t!(test19: "ABC123def456" => "abc123def456"); - t!(test20: "ABC123DEF456" => "abc123def456"); - t!(test21: "ABC123Def456" => "abc123_def456"); - t!(test22: "ABC123DEf456" => "abc123d_ef456"); - t!(test23: "ABC123dEEf456FOO" => "abc123d_e_ef456_foo"); - t!(test24: "abcDEF" => "abc_def"); - t!(test25: "ABcDE" => "a_bc_de"); -} diff --git a/third-party/vendor/heck/src/title.rs b/third-party/vendor/heck/src/title.rs deleted file mode 100644 index fdf175b7..00000000 --- a/third-party/vendor/heck/src/title.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::fmt; - -use crate::{capitalize, transform}; - -/// This trait defines a title case conversion. -/// -/// In Title Case, word boundaries are indicated by spaces, and every word is -/// capitalized. -/// -/// ## Example: -/// -/// ```rust -/// use heck::ToTitleCase; -/// -/// let sentence = "We have always lived in slums and holes in the wall."; -/// assert_eq!(sentence.to_title_case(), "We Have Always Lived In Slums And Holes In The Wall"); -/// ``` -pub trait ToTitleCase: ToOwned { - /// Convert this type to title case. - fn to_title_case(&self) -> Self::Owned; -} - -impl ToTitleCase for str { - fn to_title_case(&self) -> String { - AsTitleCase(self).to_string() - } -} - -/// This wrapper performs a title case conversion in [`fmt::Display`]. -/// -/// ## Example: -/// -/// ``` -/// use heck::AsTitleCase; -/// -/// let sentence = "We have always lived in slums and holes in the wall."; -/// assert_eq!(format!("{}", AsTitleCase(sentence)), "We Have Always Lived In Slums And Holes In The Wall"); -/// ``` -pub struct AsTitleCase>(pub T); - -impl> fmt::Display for AsTitleCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - transform(self.0.as_ref(), capitalize, |f| write!(f, " "), f) - } -} - -#[cfg(test)] -mod tests { - use super::ToTitleCase; - - macro_rules! t { - ($t:ident : $s1:expr => $s2:expr) => { - #[test] - fn $t() { - assert_eq!($s1.to_title_case(), $s2) - } - }; - } - - t!(test1: "CamelCase" => "Camel Case"); - t!(test2: "This is Human case." => "This Is Human Case"); - t!(test3: "MixedUP CamelCase, with some Spaces" => "Mixed Up Camel Case With Some Spaces"); - t!(test4: "mixed_up_ snake_case, with some _spaces" => "Mixed Up Snake Case With Some Spaces"); - t!(test5: "kebab-case" => "Kebab Case"); - t!(test6: "SHOUTY_SNAKE_CASE" => "Shouty Snake Case"); - t!(test7: "snake_case" => "Snake Case"); - t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "This Contains All Kinds Of Word Boundaries"); - #[cfg(feature = "unicode")] - t!(test9: "XΣXΣ baffle" => "Xσxς Baffle"); - t!(test10: "XMLHttpRequest" => "Xml Http Request"); -} diff --git a/third-party/vendor/heck/src/train.rs b/third-party/vendor/heck/src/train.rs deleted file mode 100644 index 04dd6a99..00000000 --- a/third-party/vendor/heck/src/train.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::fmt; - -use crate::{capitalize, transform}; - -/// This trait defines a train case conversion. -/// -/// In Train-Case, word boundaries are indicated by hyphens and words start -/// with Capital Letters. -/// -/// ## Example: -/// -/// ```rust -/// use heck::ToTrainCase; -/// -/// let sentence = "We are going to inherit the earth."; -/// assert_eq!(sentence.to_train_case(), "We-Are-Going-To-Inherit-The-Earth"); -/// ``` -pub trait ToTrainCase: ToOwned { - /// Convert this type to Train-Case. - fn to_train_case(&self) -> Self::Owned; -} - -impl ToTrainCase for str { - fn to_train_case(&self) -> Self::Owned { - AsTrainCase(self).to_string() - } -} - -/// This wrapper performs a train case conversion in [`fmt::Display`]. -/// -/// ## Example: -/// -/// ``` -/// use heck::AsTrainCase; -/// -/// let sentence = "We are going to inherit the earth."; -/// assert_eq!(format!("{}", AsTrainCase(sentence)), "We-Are-Going-To-Inherit-The-Earth"); -/// ``` -pub struct AsTrainCase>(pub T); - -impl> fmt::Display for AsTrainCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - transform(self.0.as_ref(), capitalize, |f| write!(f, "-"), f) - } -} - -#[cfg(test)] -mod tests { - use super::ToTrainCase; - - macro_rules! t { - ($t:ident : $s1:expr => $s2:expr) => { - #[test] - fn $t() { - assert_eq!($s1.to_train_case(), $s2) - } - }; - } - - t!(test1: "CamelCase" => "Camel-Case"); - t!(test2: "This is Human case." => "This-Is-Human-Case"); - t!(test3: "MixedUP CamelCase, with some Spaces" => "Mixed-Up-Camel-Case-With-Some-Spaces"); - t!(test4: "mixed_up_ snake_case with some _spaces" => "Mixed-Up-Snake-Case-With-Some-Spaces"); - t!(test5: "kebab-case" => "Kebab-Case"); - t!(test6: "SHOUTY_SNAKE_CASE" => "Shouty-Snake-Case"); - t!(test7: "snake_case" => "Snake-Case"); - t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "This-Contains-All-Kinds-Of-Word-Boundaries"); - #[cfg(feature = "unicode")] - t!(test9: "XΣXΣ baffle" => "Xσxς-Baffle"); - t!(test10: "XMLHttpRequest" => "Xml-Http-Request"); - t!(test11: "FIELD_NAME11" => "Field-Name11"); - t!(test12: "99BOTTLES" => "99bottles"); - t!(test13: "FieldNamE11" => "Field-Nam-E11"); - t!(test14: "abc123def456" => "Abc123def456"); - t!(test16: "abc123DEF456" => "Abc123-Def456"); - t!(test17: "abc123Def456" => "Abc123-Def456"); - t!(test18: "abc123DEf456" => "Abc123-D-Ef456"); - t!(test19: "ABC123def456" => "Abc123def456"); - t!(test20: "ABC123DEF456" => "Abc123def456"); - t!(test21: "ABC123Def456" => "Abc123-Def456"); - t!(test22: "ABC123DEf456" => "Abc123d-Ef456"); - t!(test23: "ABC123dEEf456FOO" => "Abc123d-E-Ef456-Foo"); - t!(test24: "abcDEF" => "Abc-Def"); - t!(test25: "ABcDE" => "A-Bc-De"); -} diff --git a/third-party/vendor/heck/src/upper_camel.rs b/third-party/vendor/heck/src/upper_camel.rs deleted file mode 100644 index 70bf4ac7..00000000 --- a/third-party/vendor/heck/src/upper_camel.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::fmt; - -use crate::{capitalize, transform}; - -/// This trait defines an upper camel case conversion. -/// -/// In UpperCamelCase, word boundaries are indicated by capital letters, -/// including the first word. -/// -/// ## Example: -/// -/// ```rust -/// use heck::ToUpperCamelCase; -/// -/// let sentence = "We are not in the least afraid of ruins."; -/// assert_eq!(sentence.to_upper_camel_case(), "WeAreNotInTheLeastAfraidOfRuins"); -/// ``` -pub trait ToUpperCamelCase: ToOwned { - /// Convert this type to upper camel case. - fn to_upper_camel_case(&self) -> Self::Owned; -} - -impl ToUpperCamelCase for str { - fn to_upper_camel_case(&self) -> String { - AsUpperCamelCase(self).to_string() - } -} - -/// ToPascalCase is an alias for ToUpperCamelCase. See ToUpperCamelCase for more -/// documentation. -pub trait ToPascalCase: ToOwned { - /// Convert this type to upper camel case. - fn to_pascal_case(&self) -> Self::Owned; -} - -impl ToPascalCase for T { - fn to_pascal_case(&self) -> Self::Owned { - self.to_upper_camel_case() - } -} - -/// This wrapper performs a upper camel case conversion in [`fmt::Display`]. -/// -/// ## Example: -/// -/// ``` -/// use heck::AsUpperCamelCase; -/// -/// let sentence = "We are not in the least afraid of ruins."; -/// assert_eq!(format!("{}", AsUpperCamelCase(sentence)), "WeAreNotInTheLeastAfraidOfRuins"); -/// ``` -pub struct AsUpperCamelCase>(pub T); - -impl> fmt::Display for AsUpperCamelCase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - transform(self.0.as_ref(), capitalize, |_| Ok(()), f) - } -} - -#[cfg(test)] -mod tests { - use super::ToUpperCamelCase; - - macro_rules! t { - ($t:ident : $s1:expr => $s2:expr) => { - #[test] - fn $t() { - assert_eq!($s1.to_upper_camel_case(), $s2) - } - }; - } - - t!(test1: "CamelCase" => "CamelCase"); - t!(test2: "This is Human case." => "ThisIsHumanCase"); - t!(test3: "MixedUP_CamelCase, with some Spaces" => "MixedUpCamelCaseWithSomeSpaces"); - t!(test4: "mixed_up_ snake_case, with some _spaces" => "MixedUpSnakeCaseWithSomeSpaces"); - t!(test5: "kebab-case" => "KebabCase"); - t!(test6: "SHOUTY_SNAKE_CASE" => "ShoutySnakeCase"); - t!(test7: "snake_case" => "SnakeCase"); - t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "ThisContainsAllKindsOfWordBoundaries"); - #[cfg(feature = "unicode")] - t!(test9: "XΣXΣ baffle" => "XσxςBaffle"); - t!(test10: "XMLHttpRequest" => "XmlHttpRequest"); -} diff --git a/third-party/vendor/indenter/.cargo-checksum.json b/third-party/vendor/indenter/.cargo-checksum.json deleted file mode 100644 index 569f4a23..00000000 --- a/third-party/vendor/indenter/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"488d07e32f0882080938c8baae0af55ea58937d816f4c4c12f294f057238b064","Cargo.lock":"3df02f6a248110ecf9527ce2ae8c3c91acc295277bd2d0745d9d1d3aa622754f","Cargo.toml":"1ee8d05e19dffa8cd49dc9f7288a30b00d598d3240a06a24298e845e9854541b","README.md":"8f9fff9b73b1205590cb57eba24c1b6e79424cea82c30eccc072d07472062cf7","examples/usage.rs":"5bb66ce0078a6cd1dded6f49122fa96c8f0842c4d6631827299ebf575dfff49d","src/lib.rs":"3e504c87e794adaa522153e350ba1cec7e4671fdb4b71309800b9bdeb6a94400"},"package":"ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"} \ No newline at end of file diff --git a/third-party/vendor/indenter/CHANGELOG.md b/third-party/vendor/indenter/CHANGELOG.md deleted file mode 100644 index 3d8a3c63..00000000 --- a/third-party/vendor/indenter/CHANGELOG.md +++ /dev/null @@ -1,31 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - - - -## [Unreleased] - ReleaseDate - -## [0.3.3] - 2021-02-22 -### Added -- Implement new code dedenting / indenting formatter by cecton - -## [0.3.2] - 2021-01-04 -### Fixed -- Changed indentation logic to better support trailing newlines and improve - overall formatting consistency - -## [0.3.1] - 2020-12-21 -### Added -- `with_str` helper method for indenting with static strings -### Changed -- Relaxed `Sized` bound on inner writers - - - -[Unreleased]: https://github.com/yaahc/indenter/compare/v0.3.3...HEAD -[0.3.3]: https://github.com/yaahc/indenter/compare/v0.3.2...v0.3.3 -[0.3.2]: https://github.com/yaahc/indenter/compare/v0.3.1...v0.3.2 -[0.3.1]: https://github.com/yaahc/indenter/releases/tag/v0.3.1 diff --git a/third-party/vendor/indenter/Cargo.lock b/third-party/vendor/indenter/Cargo.lock deleted file mode 100644 index e4e4181f..00000000 --- a/third-party/vendor/indenter/Cargo.lock +++ /dev/null @@ -1,5 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "indenter" -version = "0.3.3" diff --git a/third-party/vendor/indenter/Cargo.toml b/third-party/vendor/indenter/Cargo.toml deleted file mode 100644 index 6afb6542..00000000 --- a/third-party/vendor/indenter/Cargo.toml +++ /dev/null @@ -1,70 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "indenter" -version = "0.3.3" -authors = ["Jane Lusby "] -description = "A formatter wrapper that indents the text, designed for error display impls\n" -homepage = "https://github.com/yaahc/indenter" -documentation = "https://docs.rs/indenter" -readme = "README.md" -keywords = ["display", "fmt", "Formatter", "error"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/yaahc/indenter" -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[package.metadata.release] -no-dev-version = true - -[[package.metadata.release.pre-release-replacements]] -file = "CHANGELOG.md" -replace = "{{version}}" -search = "Unreleased" - -[[package.metadata.release.pre-release-replacements]] -exactly = 1 -file = "src/lib.rs" -replace = "#![doc(html_root_url = \"https://docs.rs/{{crate_name}}/{{version}}\")]" -search = "#!\\[doc\\(html_root_url.*" - -[[package.metadata.release.pre-release-replacements]] -exactly = 1 -file = "CHANGELOG.md" -replace = "...{{tag_name}}" -search = "\\.\\.\\.HEAD" - -[[package.metadata.release.pre-release-replacements]] -file = "CHANGELOG.md" -replace = "{{date}}" -search = "ReleaseDate" - -[[package.metadata.release.pre-release-replacements]] -exactly = 1 -file = "CHANGELOG.md" -replace = "\n\n## [Unreleased] - ReleaseDate" -search = "" - -[[package.metadata.release.pre-release-replacements]] -exactly = 1 -file = "CHANGELOG.md" -replace = "\n[Unreleased]: https://github.com/yaahc/{{crate_name}}/compare/{{tag_name}}...HEAD" -search = "" - -[dependencies] - -[features] -default = [] -std = [] diff --git a/third-party/vendor/indenter/README.md b/third-party/vendor/indenter/README.md deleted file mode 100644 index 98bce3c4..00000000 --- a/third-party/vendor/indenter/README.md +++ /dev/null @@ -1,113 +0,0 @@ -## indenter - -[![Build Status][actions-badge]][actions-url] -[![Latest Version][version-badge]][version-url] -[![Rust Documentation][docs-badge]][docs-url] - -[actions-badge]: https://github.com/yaahc/indenter/workflows/Continuous%20integration/badge.svg -[actions-url]: https://github.com/yaahc/indenter/actions?query=workflow%3A%22Continuous+integration%22 -[version-badge]: https://img.shields.io/crates/v/indenter.svg -[version-url]: https://crates.io/crates/indenter -[docs-badge]: https://img.shields.io/badge/docs-latest-blue.svg -[docs-url]: https://docs.rs/indenter - -A few wrappers for the `fmt::Write` objects that efficiently appends and remove -common indentation after every newline - -## Setup - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -indenter = "0.2" -``` - -## Examples - -## Indentation only - -This type is intended primarily for writing error reporters that gracefully -format error messages that span multiple lines. - -```rust -use std::error::Error; -use std::fmt::{self, Write}; -use indenter::indented; - -struct ErrorReporter<'a>(&'a dyn Error); - -impl fmt::Debug for ErrorReporter<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut source = Some(self.0); - let mut i = 0; - - while let Some(error) = source { - writeln!(f)?; - write!(indented(f).ind(i), "{}", error)?; - - source = error.source(); - i += 1; - } - - Ok(()) - } -} -``` - -## "Dedenting" (removing common leading indendation) - -This type is intended primarily for formatting source code. For example, when -generating code. - -This type requires the feature `std`. - -```rust -use std::error::Error; -use core::fmt::{self, Write}; -use indenter::CodeFormatter; - -let mut output = String::new(); -let mut f = CodeFormatter::new(&mut output, " "); - -write!( - f, - r#" - Hello - World - "#, -); - -assert_eq!(output, "Hello\n World\n"); - -let mut output = String::new(); -let mut f = CodeFormatter::new(&mut output, " "); - -// it can also indent... -f.indent(2); - -write!( - f, - r#" - Hello - World - "#, -); - -assert_eq!(output, " Hello\n World\n"); -``` - -#### License - - -Licensed under either of Apache License, Version -2.0 or MIT license at your option. - - -
- - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in this crate by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. - diff --git a/third-party/vendor/indenter/examples/usage.rs b/third-party/vendor/indenter/examples/usage.rs deleted file mode 100644 index 3432fccc..00000000 --- a/third-party/vendor/indenter/examples/usage.rs +++ /dev/null @@ -1,12 +0,0 @@ -use indenter::indented; -use std::fmt::Write; - -fn main() { - let input = "verify\nthis"; - let mut output = String::new(); - - indented(&mut output).ind(12).write_str(input).unwrap(); - - println!("Before:\n{}\n", input); - println!("After:\n{}", output); -} diff --git a/third-party/vendor/indenter/src/lib.rs b/third-party/vendor/indenter/src/lib.rs deleted file mode 100644 index f9b73ba7..00000000 --- a/third-party/vendor/indenter/src/lib.rs +++ /dev/null @@ -1,542 +0,0 @@ -//! A few wrappers for the `fmt::Write` objects that efficiently appends and remove -//! common indentation after every newline -//! -//! # Setup -//! -//! Add this to your `Cargo.toml`: -//! -//! ```toml -//! [dependencies] -//! indenter = "0.2" -//! ``` -//! -//! # Examples -//! -//! ## Indentation only -//! -//! This type is intended primarily for writing error reporters that gracefully -//! format error messages that span multiple lines. -//! -//! ```rust -//! use std::error::Error; -//! use core::fmt::{self, Write}; -//! use indenter::indented; -//! -//! struct ErrorReporter<'a>(&'a dyn Error); -//! -//! impl fmt::Debug for ErrorReporter<'_> { -//! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -//! let mut source = Some(self.0); -//! let mut i = 0; -//! -//! while let Some(error) = source { -//! writeln!(f)?; -//! write!(indented(f).ind(i), "{}", error)?; -//! -//! source = error.source(); -//! i += 1; -//! } -//! -//! Ok(()) -//! } -//! } -//! ``` -//! -//! ## "Dedenting" (removing common leading indendation) -//! -//! This type is intended primarily for formatting source code. For example, when -//! generating code. -//! -//! This type requires the feature `std`. -//! -//! ```rust -//! # #[cfg(feature = "std")] -//! # fn main() { -//! use std::error::Error; -//! use core::fmt::{self, Write}; -//! use indenter::CodeFormatter; -//! -//! let mut output = String::new(); -//! let mut f = CodeFormatter::new(&mut output, " "); -//! -//! write!( -//! f, -//! r#" -//! Hello -//! World -//! "#, -//! ); -//! -//! assert_eq!(output, "Hello\n World\n"); -//! -//! let mut output = String::new(); -//! let mut f = CodeFormatter::new(&mut output, " "); -//! -//! // it can also indent... -//! f.indent(2); -//! -//! write!( -//! f, -//! r#" -//! Hello -//! World -//! "#, -//! ); -//! -//! assert_eq!(output, " Hello\n World\n"); -//! # } -//! # #[cfg(not(feature = "std"))] -//! # fn main() { -//! # } -//! ``` -#![cfg_attr(not(feature = "std"), no_std)] -#![doc(html_root_url = "https://docs.rs/indenter/0.3.3")] -#![warn( - missing_debug_implementations, - missing_docs, - missing_doc_code_examples, - rust_2018_idioms, - unreachable_pub, - bad_style, - const_err, - dead_code, - improper_ctypes, - non_shorthand_field_patterns, - no_mangle_generic_items, - overflowing_literals, - path_statements, - patterns_in_fns_without_body, - private_in_public, - unconditional_recursion, - unused, - unused_allocation, - unused_comparisons, - unused_parens, - while_true -)] -use core::fmt; - -/// The set of supported formats for indentation -#[allow(missing_debug_implementations)] -pub enum Format<'a> { - /// Insert uniform indentation before every line - /// - /// This format takes a static string as input and inserts it after every newline - Uniform { - /// The string to insert as indentation - indentation: &'static str, - }, - /// Inserts a number before the first line - /// - /// This format hard codes the indentation level to match the indentation from - /// `core::backtrace::Backtrace` - Numbered { - /// The index to insert before the first line of output - ind: usize, - }, - /// A custom indenter which is executed after every newline - /// - /// Custom indenters are passed the current line number and the buffer to be written to as args - Custom { - /// The custom indenter - inserter: &'a mut Inserter, - }, -} - -/// Helper struct for efficiently indenting multi line display implementations -/// -/// # Explanation -/// -/// This type will never allocate a string to handle inserting indentation. It instead leverages -/// the `write_str` function that serves as the foundation of the `core::fmt::Write` trait. This -/// lets it intercept each piece of output as its being written to the output buffer. It then -/// splits on newlines giving slices into the original string. Finally we alternate writing these -/// lines and the specified indentation to the output buffer. -#[allow(missing_debug_implementations)] -pub struct Indented<'a, D: ?Sized> { - inner: &'a mut D, - needs_indent: bool, - format: Format<'a>, -} - -/// A callback for `Format::Custom` used to insert indenation after a new line -/// -/// The first argument is the line number within the output, starting from 0 -pub type Inserter = dyn FnMut(usize, &mut dyn fmt::Write) -> fmt::Result; - -impl Format<'_> { - fn insert_indentation(&mut self, line: usize, f: &mut dyn fmt::Write) -> fmt::Result { - match self { - Format::Uniform { indentation } => write!(f, "{}", indentation), - Format::Numbered { ind } => { - if line == 0 { - write!(f, "{: >4}: ", ind) - } else { - write!(f, " ") - } - } - Format::Custom { inserter } => inserter(line, f), - } - } -} - -impl<'a, D> Indented<'a, D> { - /// Sets the format to `Format::Numbered` with the provided index - pub fn ind(self, ind: usize) -> Self { - self.with_format(Format::Numbered { ind }) - } - - /// Sets the format to `Format::Uniform` with the provided static string - pub fn with_str(self, indentation: &'static str) -> Self { - self.with_format(Format::Uniform { indentation }) - } - - /// Construct an indenter with a user defined format - pub fn with_format(mut self, format: Format<'a>) -> Self { - self.format = format; - self - } -} - -impl fmt::Write for Indented<'_, T> -where - T: fmt::Write + ?Sized, -{ - fn write_str(&mut self, s: &str) -> fmt::Result { - for (ind, line) in s.split('\n').enumerate() { - if ind > 0 { - self.inner.write_char('\n')?; - self.needs_indent = true; - } - - if self.needs_indent { - // Don't render the line unless its actually got text on it - if line.is_empty() { - continue; - } - - self.format.insert_indentation(ind, &mut self.inner)?; - self.needs_indent = false; - } - - self.inner.write_fmt(format_args!("{}", line))?; - } - - Ok(()) - } -} - -/// Helper function for creating a default indenter -pub fn indented(f: &mut D) -> Indented<'_, D> { - Indented { - inner: f, - needs_indent: true, - format: Format::Uniform { - indentation: " ", - }, - } -} - -/// Helper struct for efficiently dedent and indent multi line display implementations -/// -/// # Explanation -/// -/// This type allocates a string once to get the formatted result and then uses the internal -/// formatter efficiently to: first dedent the output, then re-indent to the desired level. -#[cfg(feature = "std")] -#[allow(missing_debug_implementations)] -pub struct CodeFormatter<'a, T> { - f: &'a mut T, - level: u32, - indentation: String, -} - -#[cfg(feature = "std")] -impl<'a, T: fmt::Write> fmt::Write for CodeFormatter<'a, T> { - fn write_str(&mut self, input: &str) -> fmt::Result { - let input = match input.chars().next() { - Some('\n') => &input[1..], - _ => return self.f.write_str(input), - }; - - let min = input - .split('\n') - .map(|line| line.chars().take_while(char::is_ascii_whitespace).count()) - .filter(|count| *count > 0) - .min() - .unwrap_or_default(); - - let input = input.trim_end_matches(|c| char::is_ascii_whitespace(&c)); - - for line in input.split('\n') { - if line.len().saturating_sub(min) > 0 { - for _ in 0..self.level { - self.f.write_str(&self.indentation)?; - } - } - - if line.len() >= min { - self.f.write_str(&line[min..])?; - } else { - self.f.write_str(&line)?; - } - self.f.write_char('\n')?; - } - - Ok(()) - } - - fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result { - self.write_str(&args.to_string()) - } -} - -#[cfg(feature = "std")] -impl<'a, T: fmt::Write> CodeFormatter<'a, T> { - /// Wrap the formatter `f`, use `indentation` as base string indentation and return a new - /// formatter that implements `std::fmt::Write` that can be used with the macro `write!()` - pub fn new>(f: &'a mut T, indentation: S) -> Self { - Self { - f, - level: 0, - indentation: indentation.into(), - } - } - - /// Set the indentation level to a specific value - pub fn set_level(&mut self, level: u32) { - self.level = level; - } - - /// Increase the indentation level by `inc` - pub fn indent(&mut self, inc: u32) { - self.level = self.level.saturating_add(inc); - } - - /// Decrease the indentation level by `inc` - pub fn dedent(&mut self, inc: u32) { - self.level = self.level.saturating_sub(inc); - } -} - -#[cfg(test)] -mod tests { - extern crate alloc; - - use super::*; - use alloc::string::String; - use core::fmt::Write as _; - - #[test] - fn one_digit() { - let input = "verify\nthis"; - let expected = " 2: verify\n this"; - let mut output = String::new(); - - indented(&mut output).ind(2).write_str(input).unwrap(); - - assert_eq!(expected, output); - } - - #[test] - fn two_digits() { - let input = "verify\nthis"; - let expected = " 12: verify\n this"; - let mut output = String::new(); - - indented(&mut output).ind(12).write_str(input).unwrap(); - - assert_eq!(expected, output); - } - - #[test] - fn no_digits() { - let input = "verify\nthis"; - let expected = " verify\n this"; - let mut output = String::new(); - - indented(&mut output).write_str(input).unwrap(); - - assert_eq!(expected, output); - } - - #[test] - fn with_str() { - let input = "verify\nthis"; - let expected = "...verify\n...this"; - let mut output = String::new(); - - indented(&mut output) - .with_str("...") - .write_str(input) - .unwrap(); - - assert_eq!(expected, output); - } - - #[test] - fn dyn_write() { - let input = "verify\nthis"; - let expected = " verify\n this"; - let mut output = String::new(); - let writer: &mut dyn core::fmt::Write = &mut output; - - indented(writer).write_str(input).unwrap(); - - assert_eq!(expected, output); - } - - #[test] - fn nice_api() { - let input = "verify\nthis"; - let expected = " 1: verify\n this"; - let output = &mut String::new(); - let n = 1; - - write!( - indented(output).with_format(Format::Custom { - inserter: &mut move |line_no, f| { - if line_no == 0 { - write!(f, "{: >4}: ", n) - } else { - write!(f, " ") - } - } - }), - "{}", - input - ) - .unwrap(); - - assert_eq!(expected, output); - } - - #[test] - fn nice_api_2() { - let input = "verify\nthis"; - let expected = " verify\n this"; - let output = &mut String::new(); - - write!( - indented(output).with_format(Format::Uniform { indentation: " " }), - "{}", - input - ) - .unwrap(); - - assert_eq!(expected, output); - } - - #[test] - fn trailing_newlines() { - let input = "verify\nthis\n"; - let expected = " verify\n this\n"; - let output = &mut String::new(); - - write!(indented(output).with_str(" "), "{}", input).unwrap(); - - assert_eq!(expected, output); - } - - #[test] - fn several_interpolations() { - let input = "verify\nthis\n"; - let expected = " verify\n this\n and verify\n this\n"; - let output = &mut String::new(); - - write!(indented(output).with_str(" "), "{} and {}", input, input).unwrap(); - - assert_eq!(expected, output); - } -} - -#[cfg(all(test, feature = "std"))] -mod tests_std { - use super::*; - use core::fmt::Write as _; - - #[test] - fn dedent() { - let mut s = String::new(); - let mut f = CodeFormatter::new(&mut s, " "); - write!( - f, - r#" - struct Foo; - - impl Foo {{ - fn foo() {{ - todo!() - }} - }} - "#, - ) - .unwrap(); - assert_eq!( - s, - "struct Foo;\n\nimpl Foo {\n fn foo() {\n todo!()\n }\n}\n" - ); - - let mut s = String::new(); - let mut f = CodeFormatter::new(&mut s, " "); - write!( - f, - r#" - struct Foo; - - impl Foo {{ - fn foo() {{ - todo!() - }} - }}"#, - ) - .unwrap(); - assert_eq!( - s, - "struct Foo;\n\nimpl Foo {\n fn foo() {\n todo!()\n }\n}\n" - ); - } - - #[test] - fn indent() { - let mut s = String::new(); - let mut f = CodeFormatter::new(&mut s, " "); - f.indent(1); - write!( - f, - r#" - struct Foo; - - impl Foo {{ - fn foo() {{ - todo!() - }} - }} - "#, - ) - .unwrap(); - assert_eq!(s, " struct Foo;\n\n impl Foo {\n fn foo() {\n todo!()\n }\n }\n"); - } - - #[test] - fn inline() { - let mut s = String::new(); - let mut f = CodeFormatter::new(&mut s, " "); - write!( - f, - r#"struct Foo; - fn foo() {{ - }}"#, - ) - .unwrap(); - assert_eq!(s, "struct Foo;\n fn foo() {\n }"); - } - - #[test] - fn split_prefix() { - let mut s = String::new(); - let mut f = CodeFormatter::new(&mut s, " "); - writeln!(f).unwrap(); - assert_eq!(s, "\n"); - } -} diff --git a/third-party/vendor/salsa-2022-macros/.cargo-checksum.json b/third-party/vendor/salsa-2022-macros/.cargo-checksum.json deleted file mode 100644 index 4b1e0d49..00000000 --- a/third-party/vendor/salsa-2022-macros/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"f52122185e9c1ed013834e800b45aa8481559ed2f01ed518ff0a7ae9ad8886bd","src/accumulator.rs":"4da510729f72652abdd9a09a5a962fa0cad25339b04838638d4a20133c0298e2","src/configuration.rs":"4d47f6ad909966ac201d3346925bf177997d875b1f858896e9fb4b25ac84b4fe","src/db.rs":"202d18bc346585376b5df00e5a42aace0ed6f0b06c0ab888e69f31ae0f02eca9","src/input.rs":"f5f5628b4b65f7f6be336bfd052fd052f23c9a517cc15052843a046b7c5ae7c9","src/interned.rs":"06b10fa5afd46f5e093ce5c242e9975be54355fb19560f429d1e8f494e68173b","src/jar.rs":"472f9a72af791b236e233136031ec3df642e39fd42ea6d554cdac7c9c844f6b1","src/lib.rs":"f3d2284a4c9f62365466a314e5072cd9eedb43fa005c4b688516bb6fa482358a","src/options.rs":"ee18e422f9589e07691895b7cc6f0baa8129ffd7293e0a59db6c03a6b1a6279d","src/salsa_struct.rs":"9a132d5fab49060e6c9cfb634e6cd62550736b826b67c8e23b4827e90926e052","src/tracked.rs":"e7e6af1e0ec5e73578419e0a36e8f7ff4f38c6e4d25ccffba045cb5c8193c942","src/tracked_fn.rs":"2ee1897ccd6880a56198911748ebaeabb9b534d6bc0c42fc3d7a03d2777c4a3a","src/tracked_struct.rs":"24a511419588071c5f26a96ba5980ccb031aeecc510eddb0e52238945d287f91"},"package":null} \ No newline at end of file diff --git a/third-party/vendor/salsa-2022-macros/Cargo.toml b/third-party/vendor/salsa-2022-macros/Cargo.toml deleted file mode 100644 index f73eadf4..00000000 --- a/third-party/vendor/salsa-2022-macros/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "salsa-2022-macros" -version = "0.1.0" - -[lib] -proc-macro = true - -[dependencies] -eyre = "0.6.5" -heck = "0.4" -proc-macro2 = "1.0" -quote = "1.0" - -[dependencies.syn] -version = "1.0" -features = [ - "full", - "extra-traits", - "visit-mut", -] diff --git a/third-party/vendor/salsa-2022-macros/src/accumulator.rs b/third-party/vendor/salsa-2022-macros/src/accumulator.rs deleted file mode 100644 index 3fc9e223..00000000 --- a/third-party/vendor/salsa-2022-macros/src/accumulator.rs +++ /dev/null @@ -1,162 +0,0 @@ -use syn::ItemStruct; - -// #[salsa::accumulator(jar = Jar0)] -// struct Accumulator(DataType); - -pub(crate) fn accumulator( - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - let args = syn::parse_macro_input!(args as Args); - let struct_impl = syn::parse_macro_input!(input as ItemStruct); - accumulator_contents(&args, &struct_impl) - .unwrap_or_else(syn::Error::into_compile_error) - .into() -} - -type Args = crate::options::Options; - -struct Accumulator; - -impl crate::options::AllowedOptions for Accumulator { - const RETURN_REF: bool = false; - - const SPECIFY: bool = false; - - const NO_EQ: bool = false; - - const SINGLETON: bool = false; - - const JAR: bool = true; - - const DATA: bool = false; - - const DB: bool = false; - - const RECOVERY_FN: bool = false; - - const LRU: bool = false; - - const CONSTRUCTOR_NAME: bool = false; -} - -fn accumulator_contents( - args: &Args, - struct_item: &syn::ItemStruct, -) -> syn::Result { - // We expect a single anonymous field. - let data_ty = data_ty(struct_item)?; - let struct_name = &struct_item.ident; - let struct_ty = &parse_quote! {#struct_name}; - - let inherent_impl = inherent_impl(args, struct_ty, data_ty); - let ingredients_for_impl = ingredients_for_impl(args, struct_name, data_ty); - let struct_item_out = struct_item_out(args, struct_item, data_ty); - let accumulator_impl = accumulator_impl(args, struct_ty, data_ty); - - Ok(quote! { - #inherent_impl - #ingredients_for_impl - #struct_item_out - #accumulator_impl - }) -} - -fn data_ty(struct_item: &syn::ItemStruct) -> syn::Result<&syn::Type> { - if let syn::Fields::Unnamed(fields) = &struct_item.fields { - if fields.unnamed.len() != 1 { - Err(syn::Error::new( - struct_item.ident.span(), - "accumulator structs should have only one anonymous field", - )) - } else { - Ok(&fields.unnamed[0].ty) - } - } else { - Err(syn::Error::new( - struct_item.ident.span(), - "accumulator structs should have only one anonymous field", - )) - } -} - -fn struct_item_out( - _args: &Args, - struct_item: &syn::ItemStruct, - data_ty: &syn::Type, -) -> syn::ItemStruct { - let mut struct_item_out = struct_item.clone(); - struct_item_out.fields = syn::Fields::Unnamed(parse_quote! { - (std::marker::PhantomData<#data_ty>) - }); - struct_item_out -} - -fn inherent_impl(args: &Args, struct_ty: &syn::Type, data_ty: &syn::Type) -> syn::ItemImpl { - let jar_ty = args.jar_ty(); - parse_quote! { - impl #struct_ty { - pub fn push(db: &DB, data: #data_ty) - where - DB: salsa::storage::HasJar<#jar_ty>, - { - let (jar, runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(db); - let ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #struct_ty >>::ingredient(jar); - ingredients.push(runtime, data) - } - } - } -} - -fn ingredients_for_impl( - args: &Args, - struct_name: &syn::Ident, - data_ty: &syn::Type, -) -> syn::ItemImpl { - let jar_ty = args.jar_ty(); - let debug_name = crate::literal(struct_name); - parse_quote! { - impl salsa::storage::IngredientsFor for #struct_name { - type Ingredients = salsa::accumulator::AccumulatorIngredient<#data_ty>; - type Jar = #jar_ty; - - fn create_ingredients(routes: &mut salsa::routes::Routes) -> Self::Ingredients - where - DB: salsa::DbWithJar + salsa::storage::JarFromJars, - { - let index = routes.push( - |jars| { - let jar = >::jar_from_jars(jars); - <_ as salsa::storage::HasIngredientsFor>::ingredient(jar) - }, - |jars| { - let jar = >::jar_from_jars_mut(jars); - <_ as salsa::storage::HasIngredientsFor>::ingredient_mut(jar) - }, - ); - salsa::accumulator::AccumulatorIngredient::new(index, #debug_name) - } - } - } -} - -fn accumulator_impl(args: &Args, struct_ty: &syn::Type, data_ty: &syn::Type) -> syn::ItemImpl { - let jar_ty = args.jar_ty(); - parse_quote! { - impl salsa::accumulator::Accumulator for #struct_ty { - type Data = #data_ty; - type Jar = #jar_ty; - - fn accumulator_ingredient<'db, Db>( - db: &'db Db, - ) -> &'db salsa::accumulator::AccumulatorIngredient - where - Db: ?Sized + salsa::storage::HasJar - { - let (jar, _) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(db); - let ingredients = <#jar_ty as salsa::storage::HasIngredientsFor<#struct_ty>>::ingredient(jar); - ingredients - } - } - } -} diff --git a/third-party/vendor/salsa-2022-macros/src/configuration.rs b/third-party/vendor/salsa-2022-macros/src/configuration.rs deleted file mode 100644 index 12a03bc9..00000000 --- a/third-party/vendor/salsa-2022-macros/src/configuration.rs +++ /dev/null @@ -1,94 +0,0 @@ -pub(crate) struct Configuration { - pub(crate) jar_ty: syn::Type, - pub(crate) salsa_struct_ty: syn::Type, - pub(crate) key_ty: syn::Type, - pub(crate) value_ty: syn::Type, - pub(crate) cycle_strategy: CycleRecoveryStrategy, - pub(crate) backdate_fn: syn::ImplItemMethod, - pub(crate) execute_fn: syn::ImplItemMethod, - pub(crate) recover_fn: syn::ImplItemMethod, -} - -impl Configuration { - pub(crate) fn to_impl(&self, self_ty: &syn::Type) -> syn::ItemImpl { - let Configuration { - jar_ty, - salsa_struct_ty, - key_ty, - value_ty, - cycle_strategy, - backdate_fn, - execute_fn, - recover_fn, - } = self; - parse_quote! { - impl salsa::function::Configuration for #self_ty { - type Jar = #jar_ty; - type SalsaStruct = #salsa_struct_ty; - type Key = #key_ty; - type Value = #value_ty; - const CYCLE_STRATEGY: salsa::cycle::CycleRecoveryStrategy = #cycle_strategy; - #backdate_fn - #execute_fn - #recover_fn - } - } - } -} - -pub(crate) enum CycleRecoveryStrategy { - Panic, - Fallback, -} - -impl quote::ToTokens for CycleRecoveryStrategy { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - match self { - CycleRecoveryStrategy::Panic => { - tokens.extend(quote! {salsa::cycle::CycleRecoveryStrategy::Panic}) - } - CycleRecoveryStrategy::Fallback => { - tokens.extend(quote! {salsa::cycle::CycleRecoveryStrategy::Fallback}) - } - } - } -} - -/// Returns an appropriate definition for `should_backdate_value` depending on -/// whether this value is memoized or not. -pub(crate) fn should_backdate_value_fn(should_backdate: bool) -> syn::ImplItemMethod { - if should_backdate { - parse_quote! { - fn should_backdate_value(v1: &Self::Value, v2: &Self::Value) -> bool { - salsa::function::should_backdate_value(v1, v2) - } - } - } else { - parse_quote! { - fn should_backdate_value(_v1: &Self::Value, _v2: &Self::Value) -> bool { - false - } - } - } -} - -/// Returns an appropriate definition for `recover_from_cycle` for cases where -/// the cycle recovery is panic. -pub(crate) fn panic_cycle_recovery_fn() -> syn::ImplItemMethod { - parse_quote! { - fn recover_from_cycle( - _db: &salsa::function::DynDb, - _cycle: &salsa::Cycle, - _key: Self::Key, - ) -> Self::Value { - panic!() - } - } -} - -pub(crate) fn value_ty(sig: &syn::Signature) -> syn::Type { - match &sig.output { - syn::ReturnType::Default => parse_quote!(()), - syn::ReturnType::Type(_, ty) => syn::Type::clone(ty), - } -} diff --git a/third-party/vendor/salsa-2022-macros/src/db.rs b/third-party/vendor/salsa-2022-macros/src/db.rs deleted file mode 100644 index 6fa2a989..00000000 --- a/third-party/vendor/salsa-2022-macros/src/db.rs +++ /dev/null @@ -1,233 +0,0 @@ -use proc_macro2::Literal; -use syn::{spanned::Spanned, Token}; - -// Source: -// -// #[salsa::db(Jar0, Jar1, Jar2)] -// pub struct Database { -// storage: salsa::Storage, -// } - -pub(crate) fn db( - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - let args = syn::parse_macro_input!(args as Args); - let input = syn::parse_macro_input!(input as syn::ItemStruct); - let storage = match find_storage_field(&input) { - Ok(v) => v, - Err(err) => { - let err = Literal::string(err); - let error = quote_spanned!(input.ident.span() => compile_error!(#err)); - return quote! { - #input - #error - } - .into(); - } - }; - - let as_salsa_database_impl = as_salsa_database_impl(&input); - let has_jars_impl = has_jars_impl(&args, &input, &storage); - let has_jars_dyn_impl = has_jars_dyn_impl(&input, &storage); - let per_jar_impls = per_jar_impls(&args, &input, &storage); - - quote! { - #input - #as_salsa_database_impl - #has_jars_impl - #has_jars_dyn_impl - #(#per_jar_impls)* - } - .into() -} - -pub struct Args { - jar_paths: syn::punctuated::Punctuated, -} - -impl syn::parse::Parse for Args { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result { - Ok(Self { - jar_paths: syn::punctuated::Punctuated::parse_terminated(input)?, - }) - } -} - -fn find_storage_field(input: &syn::ItemStruct) -> Result { - let storage = "storage"; - for field in input.fields.iter() { - if let Some(i) = &field.ident { - if i == storage { - return Ok(i.clone()); - } - } else { - return Err( - "database struct must be a braced struct (`{}`) with a field named storage", - ); - } - } - - Err("database has no field named `storage`") -} - -fn as_salsa_database_impl(input: &syn::ItemStruct) -> syn::ItemImpl { - let db = &input.ident; - parse_quote! { - impl salsa::database::AsSalsaDatabase for #db { - fn as_salsa_database(&self) -> &dyn salsa::Database { - self - } - } - } -} - -fn has_jars_impl(args: &Args, input: &syn::ItemStruct, storage: &syn::Ident) -> syn::ItemImpl { - let jar_paths: Vec<&syn::Path> = args.jar_paths.iter().collect(); - let jar_field_names: Vec<_> = args - .jar_paths - .iter() - .zip(0..) - .map(|(p, i)| syn::LitInt::new(&format!("{}", i), p.span())) - .collect(); - let db = &input.ident; - parse_quote! { - // ANCHOR: HasJars - impl salsa::storage::HasJars for #db { - type Jars = (#(#jar_paths,)*); - // ANCHOR_END: HasJars - - fn jars(&self) -> (&Self::Jars, &salsa::Runtime) { - self.#storage.jars() - } - - fn jars_mut(&mut self) -> (&mut Self::Jars, &mut salsa::Runtime) { - self.#storage.jars_mut() - } - - // ANCHOR: create_jars - fn create_jars(routes: &mut salsa::routes::Routes) -> Box { - unsafe { - salsa::plumbing::create_jars_inplace::<#db>(|jars| { - #( - unsafe { - let place = std::ptr::addr_of_mut!((*jars).#jar_field_names); - <#jar_paths as salsa::jar::Jar>::init_jar(place, routes); - } - )* - }) - } - } - // ANCHOR_END: create_jars - } - } -} - -fn has_jars_dyn_impl(input: &syn::ItemStruct, storage: &syn::Ident) -> syn::ItemImpl { - let db = &input.ident; - parse_quote! { - impl salsa::storage::HasJarsDyn for #db { - fn runtime(&self) -> &salsa::Runtime { - self.#storage.runtime() - } - - fn runtime_mut(&mut self) ->&mut salsa::Runtime { - self.#storage.runtime_mut() - } - - fn maybe_changed_after( - &self, - input: salsa::key::DependencyIndex, - revision: salsa::Revision, - ) -> bool { - let ingredient = self.#storage.ingredient(input.ingredient_index()); - ingredient.maybe_changed_after(self, input, revision) - } - - fn cycle_recovery_strategy( - &self, - ingredient_index: salsa::IngredientIndex, - ) -> salsa::cycle::CycleRecoveryStrategy { - let ingredient = self.#storage.ingredient(ingredient_index); - ingredient.cycle_recovery_strategy() - } - - fn origin( - &self, - index: salsa::DatabaseKeyIndex, - ) -> Option { - let ingredient = self.#storage.ingredient(index.ingredient_index()); - ingredient.origin(index.key_index()) - } - - fn mark_validated_output(&self, executor: salsa::DatabaseKeyIndex, output: salsa::key::DependencyIndex) { - let ingredient = self.#storage.ingredient(output.ingredient_index()); - ingredient.mark_validated_output(self, executor, output.key_index()); - } - - fn remove_stale_output(&self, executor: salsa::DatabaseKeyIndex, stale_output: salsa::key::DependencyIndex) { - let ingredient = self.#storage.ingredient(stale_output.ingredient_index()); - ingredient.remove_stale_output(self, executor, stale_output.key_index()); - } - - fn salsa_struct_deleted(&self, ingredient: salsa::IngredientIndex, id: salsa::Id) { - let ingredient = self.#storage.ingredient(ingredient); - ingredient.salsa_struct_deleted(self, id); - } - - fn fmt_index(&self, index: salsa::key::DependencyIndex, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let ingredient = self.#storage.ingredient(index.ingredient_index()); - ingredient.fmt_index(index.key_index(), fmt) - } - } - } -} - -fn per_jar_impls(args: &Args, input: &syn::ItemStruct, storage: &syn::Ident) -> Vec { - let db = &input.ident; - args.jar_paths - .iter() - .zip(0..) - .flat_map(|(jar_path, jar_index)| { - let jar_index = Literal::u32_unsuffixed(jar_index); - vec![ - parse_quote! { - impl salsa::storage::DbWithJar<#jar_path> for #db { - fn as_jar_db<'db>(&'db self) -> &'db <#jar_path as salsa::jar::Jar<'db>>::DynDb - where - 'db: 'db, - { - self as &'db <#jar_path as salsa::jar::Jar<'db>>::DynDb - } - } - }, - - parse_quote! { - impl salsa::storage::HasJar<#jar_path> for #db { - fn jar(&self) -> (&#jar_path, &salsa::Runtime) { - let (__jars, __runtime) = self.#storage.jars(); - (&__jars.#jar_index, __runtime) - } - - fn jar_mut(&mut self) -> (&mut #jar_path, &mut salsa::Runtime) { - let (__jars, __runtime) = self.#storage.jars_mut(); - (&mut __jars.#jar_index, __runtime) - } - } - }, - - parse_quote! { - impl salsa::storage::JarFromJars<#jar_path> for #db { - fn jar_from_jars<'db>(jars: &Self::Jars) -> &#jar_path { - &jars.#jar_index - } - - fn jar_from_jars_mut<'db>(jars: &mut Self::Jars) -> &mut #jar_path { - &mut jars.#jar_index - } - } - } - ] - }) - .collect() -} diff --git a/third-party/vendor/salsa-2022-macros/src/input.rs b/third-party/vendor/salsa-2022-macros/src/input.rs deleted file mode 100644 index 5b83efe6..00000000 --- a/third-party/vendor/salsa-2022-macros/src/input.rs +++ /dev/null @@ -1,321 +0,0 @@ -use crate::salsa_struct::{SalsaField, SalsaStruct, SalsaStructKind}; -use proc_macro2::{Literal, TokenStream}; - -/// For an entity struct `Foo` with fields `f1: T1, ..., fN: TN`, we generate... -/// -/// * the "id struct" `struct Foo(salsa::Id)` -/// * the entity ingredient, which maps the id fields to the `Id` -/// * for each value field, a function ingredient -pub(crate) fn input( - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - match SalsaStruct::new(SalsaStructKind::Input, args, input) - .and_then(|el| InputStruct(el).generate_input()) - { - Ok(s) => s.into(), - Err(err) => err.into_compile_error().into(), - } -} - -struct InputStruct(SalsaStruct); - -impl std::ops::Deref for InputStruct { - type Target = SalsaStruct; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl crate::options::AllowedOptions for InputStruct { - const RETURN_REF: bool = false; - - const SPECIFY: bool = false; - - const NO_EQ: bool = false; - const SINGLETON: bool = true; - - const JAR: bool = true; - - const DATA: bool = true; - - const DB: bool = false; - - const RECOVERY_FN: bool = false; - - const LRU: bool = false; - - const CONSTRUCTOR_NAME: bool = true; -} - -impl InputStruct { - fn generate_input(&self) -> syn::Result { - let id_struct = self.id_struct(); - let inherent_impl = self.input_inherent_impl(); - let ingredients_for_impl = self.input_ingredients(); - let as_id_impl = self.as_id_impl(); - let salsa_struct_in_db_impl = self.salsa_struct_in_db_impl(); - let as_debug_with_db_impl = self.as_debug_with_db_impl(); - - Ok(quote! { - #id_struct - #inherent_impl - #ingredients_for_impl - #as_id_impl - #as_debug_with_db_impl - #salsa_struct_in_db_impl - }) - } - - /// Generate an inherent impl with methods on the entity type. - fn input_inherent_impl(&self) -> syn::ItemImpl { - let ident = self.id_ident(); - let jar_ty = self.jar_ty(); - let db_dyn_ty = self.db_dyn_ty(); - let input_index = self.input_index(); - - let field_indices = self.all_field_indices(); - let field_names = self.all_field_names(); - let field_vises = self.all_field_vises(); - let field_tys: Vec<_> = self.all_field_tys(); - let field_clones: Vec<_> = self.all_fields().map(SalsaField::is_clone_field).collect(); - let get_field_names: Vec<_> = self.all_get_field_names(); - let field_getters: Vec = field_indices.iter().zip(&get_field_names).zip(&field_vises).zip(&field_tys).zip(&field_clones).map(|((((field_index, get_field_name), field_vis), field_ty), is_clone_field)| - if !*is_clone_field { - parse_quote! { - #field_vis fn #get_field_name<'db>(self, __db: &'db #db_dyn_ty) -> &'db #field_ty - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - __ingredients.#field_index.fetch(__runtime, self) - } - } - } else { - parse_quote! { - #field_vis fn #get_field_name<'db>(self, __db: &'db #db_dyn_ty) -> #field_ty - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - __ingredients.#field_index.fetch(__runtime, self).clone() - } - } - } - ) - .collect(); - - // setters - let set_field_names = self.all_set_field_names(); - let field_setters: Vec = field_indices.iter() - .zip(&set_field_names) - .zip(&field_vises) - .zip(&field_tys) - .filter_map(|(((field_index, &set_field_name), field_vis), field_ty)| { - let set_field_name = set_field_name?; - Some(parse_quote! { - #field_vis fn #set_field_name<'db>(self, __db: &'db mut #db_dyn_ty) -> salsa::setter::Setter<'db, #ident, #field_ty> - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar_mut(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient_mut(__jar); - salsa::setter::Setter::new(__runtime, self, &mut __ingredients.#field_index) - } - }) - }) - .collect(); - - let constructor_name = self.constructor_name(); - let singleton = self.0.is_isingleton(); - - let constructor: syn::ImplItemMethod = if singleton { - parse_quote! { - /// Creates a new singleton input - /// - /// # Panics - /// - /// If called when an instance already exists - pub fn #constructor_name(__db: &#db_dyn_ty, #(#field_names: #field_tys,)*) -> Self - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - let __id = __ingredients.#input_index.new_singleton_input(__runtime); - #( - __ingredients.#field_indices.store_new(__runtime, __id, #field_names, salsa::Durability::LOW); - )* - __id - } - } - } else { - parse_quote! { - pub fn #constructor_name(__db: &#db_dyn_ty, #(#field_names: #field_tys,)*) -> Self - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - let __id = __ingredients.#input_index.new_input(__runtime); - #( - __ingredients.#field_indices.store_new(__runtime, __id, #field_names, salsa::Durability::LOW); - )* - __id - } - } - }; - - if singleton { - let get: syn::ImplItemMethod = parse_quote! { - #[track_caller] - pub fn get(__db: &#db_dyn_ty) -> Self { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - __ingredients.#input_index.get_singleton_input(__runtime).expect("singleton input struct not yet initialized") - } - }; - - let try_get: syn::ImplItemMethod = parse_quote! { - #[track_caller] - pub fn try_get(__db: &#db_dyn_ty) -> Option { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - __ingredients.#input_index.get_singleton_input(__runtime) - } - }; - - parse_quote! { - impl #ident { - #constructor - - #get - - #try_get - - #(#field_getters)* - - #(#field_setters)* - } - } - } else { - parse_quote! { - impl #ident { - #constructor - - #(#field_getters)* - - #(#field_setters)* - } - } - } - - // } - } - - /// Generate the `IngredientsFor` impl for this entity. - /// - /// The entity's ingredients include both the main entity ingredient along with a - /// function ingredient for each of the value fields. - fn input_ingredients(&self) -> syn::ItemImpl { - use crate::literal; - let ident = self.id_ident(); - let field_ty = self.all_field_tys(); - let jar_ty = self.jar_ty(); - let all_field_indices: Vec = self.all_field_indices(); - let input_index: Literal = self.input_index(); - let debug_name_struct = literal(self.id_ident()); - let debug_name_fields: Vec<_> = self.all_field_names().into_iter().map(literal).collect(); - - parse_quote! { - impl salsa::storage::IngredientsFor for #ident { - type Jar = #jar_ty; - type Ingredients = ( - #( - salsa::input_field::InputFieldIngredient<#ident, #field_ty>, - )* - salsa::input::InputIngredient<#ident>, - ); - - fn create_ingredients( - routes: &mut salsa::routes::Routes, - ) -> Self::Ingredients - where - DB: salsa::DbWithJar + salsa::storage::JarFromJars, - { - ( - #( - { - let index = routes.push( - |jars| { - let jar = >::jar_from_jars(jars); - let ingredients = <_ as salsa::storage::HasIngredientsFor>::ingredient(jar); - &ingredients.#all_field_indices - }, - |jars| { - let jar = >::jar_from_jars_mut(jars); - let ingredients = <_ as salsa::storage::HasIngredientsFor>::ingredient_mut(jar); - &mut ingredients.#all_field_indices - }, - ); - salsa::input_field::InputFieldIngredient::new(index, #debug_name_fields) - }, - )* - { - let index = routes.push( - |jars| { - let jar = >::jar_from_jars(jars); - let ingredients = <_ as salsa::storage::HasIngredientsFor>::ingredient(jar); - &ingredients.#input_index - }, - |jars| { - let jar = >::jar_from_jars_mut(jars); - let ingredients = <_ as salsa::storage::HasIngredientsFor>::ingredient_mut(jar); - &mut ingredients.#input_index - }, - ); - salsa::input::InputIngredient::new(index, #debug_name_struct) - }, - ) - } - } - } - } - - /// For the entity, we create a tuple that contains the function ingredients - /// for each "other" field and the entity ingredient. This is the index of - /// the entity ingredient within that tuple. - fn input_index(&self) -> Literal { - Literal::usize_unsuffixed(self.all_fields().count()) - } - - /// For the entity, we create a tuple that contains the function ingredients - /// for each field and an entity ingredient. These are the indices - /// of the function ingredients within that tuple. - fn all_field_indices(&self) -> Vec { - self.all_fields() - .zip(0..) - .map(|(_, i)| Literal::usize_unsuffixed(i)) - .collect() - } - - /// Names of setters of all fields that should be generated. Returns an optional Ident for the field name - /// that is None when the field should not generate a setter. - /// - /// Setters are not created for fields with #[id] tag so they'll be safe to include in debug formatting - pub(crate) fn all_set_field_names(&self) -> Vec> { - self.all_fields() - .map(|ef| (!ef.has_id_attr).then(|| ef.set_name())) - .collect() - } - - /// Implementation of `SalsaStructInDb`. - fn salsa_struct_in_db_impl(&self) -> syn::ItemImpl { - let ident = self.id_ident(); - let jar_ty = self.jar_ty(); - parse_quote! { - impl salsa::salsa_struct::SalsaStructInDb for #ident - where - DB: ?Sized + salsa::DbWithJar<#jar_ty>, - { - fn register_dependent_fn(_db: &DB, _index: salsa::routes::IngredientIndex) { - // Do nothing here, at least for now. - // If/when we add ability to delete inputs, this would become relevant. - } - } - } - } -} diff --git a/third-party/vendor/salsa-2022-macros/src/interned.rs b/third-party/vendor/salsa-2022-macros/src/interned.rs deleted file mode 100644 index a53ff5f1..00000000 --- a/third-party/vendor/salsa-2022-macros/src/interned.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::salsa_struct::{SalsaStruct, SalsaStructKind}; -use proc_macro2::TokenStream; - -// #[salsa::interned(jar = Jar0, data = TyData0)] -// #[derive(Eq, PartialEq, Hash, Debug, Clone)] -// struct Ty0 { -// field1: Type1, -// #[id(ref)] field2: Type2, -// ... -// } - -pub(crate) fn interned( - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - match SalsaStruct::new(SalsaStructKind::Interned, args, input) - .and_then(|el| InternedStruct(el).generate_interned()) - { - Ok(s) => s.into(), - Err(err) => err.into_compile_error().into(), - } -} - -struct InternedStruct(SalsaStruct); - -impl std::ops::Deref for InternedStruct { - type Target = SalsaStruct; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl crate::options::AllowedOptions for InternedStruct { - const RETURN_REF: bool = false; - - const SPECIFY: bool = false; - - const NO_EQ: bool = false; - - const SINGLETON: bool = false; - - const JAR: bool = true; - - const DATA: bool = true; - - const DB: bool = false; - - const RECOVERY_FN: bool = false; - - const LRU: bool = false; - - const CONSTRUCTOR_NAME: bool = true; -} - -impl InternedStruct { - fn generate_interned(&self) -> syn::Result { - self.validate_interned()?; - let id_struct = self.id_struct(); - let data_struct = self.data_struct(); - let ingredients_for_impl = self.ingredients_for_impl(); - let as_id_impl = self.as_id_impl(); - let named_fields_impl = self.inherent_impl_for_named_fields(); - let salsa_struct_in_db_impl = self.salsa_struct_in_db_impl(); - let as_debug_with_db_impl = self.as_debug_with_db_impl(); - - Ok(quote! { - #id_struct - #data_struct - #ingredients_for_impl - #as_id_impl - #named_fields_impl - #salsa_struct_in_db_impl - #as_debug_with_db_impl - }) - } - - fn validate_interned(&self) -> syn::Result<()> { - self.disallow_id_fields("interned")?; - Ok(()) - } - - /// If this is an interned struct, then generate methods to access each field, - /// as well as a `new` method. - fn inherent_impl_for_named_fields(&self) -> syn::ItemImpl { - let vis = self.visibility(); - let id_ident = self.id_ident(); - let db_dyn_ty = self.db_dyn_ty(); - let jar_ty = self.jar_ty(); - - let field_getters: Vec = self - .all_fields() - .map(|field| { - let field_name = field.name(); - let field_ty = field.ty(); - let field_vis = field.vis(); - let field_get_name = field.get_name(); - if field.is_clone_field() { - parse_quote! { - #field_vis fn #field_get_name(self, db: &#db_dyn_ty) -> #field_ty { - let (jar, runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(db); - let ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #id_ident >>::ingredient(jar); - std::clone::Clone::clone(&ingredients.data(runtime, self).#field_name) - } - } - } else { - parse_quote! { - #field_vis fn #field_get_name<'db>(self, db: &'db #db_dyn_ty) -> &'db #field_ty { - let (jar, runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(db); - let ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #id_ident >>::ingredient(jar); - &ingredients.data(runtime, self).#field_name - } - } - } - }) - .collect(); - - let field_names = self.all_field_names(); - let field_tys = self.all_field_tys(); - let data_ident = self.data_ident(); - let constructor_name = self.constructor_name(); - let new_method: syn::ImplItemMethod = parse_quote! { - #vis fn #constructor_name( - db: &#db_dyn_ty, - #(#field_names: #field_tys,)* - ) -> Self { - let (jar, runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(db); - let ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #id_ident >>::ingredient(jar); - ingredients.intern(runtime, #data_ident { - #(#field_names,)* - }) - } - }; - - parse_quote! { - impl #id_ident { - #(#field_getters)* - - #new_method - } - } - } - - /// Generates an impl of `salsa::storage::IngredientsFor`. - /// - /// For a memoized type, the only ingredient is an `InternedIngredient`. - fn ingredients_for_impl(&self) -> syn::ItemImpl { - let id_ident = self.id_ident(); - let debug_name = crate::literal(id_ident); - let jar_ty = self.jar_ty(); - let data_ident = self.data_ident(); - parse_quote! { - impl salsa::storage::IngredientsFor for #id_ident { - type Jar = #jar_ty; - type Ingredients = salsa::interned::InternedIngredient<#id_ident, #data_ident>; - - fn create_ingredients( - routes: &mut salsa::routes::Routes, - ) -> Self::Ingredients - where - DB: salsa::storage::JarFromJars, - { - let index = routes.push( - |jars| { - let jar = >::jar_from_jars(jars); - <_ as salsa::storage::HasIngredientsFor>::ingredient(jar) - }, - |jars| { - let jar = >::jar_from_jars_mut(jars); - <_ as salsa::storage::HasIngredientsFor>::ingredient_mut(jar) - }, - ); - salsa::interned::InternedIngredient::new(index, #debug_name) - } - } - } - } - - /// Implementation of `SalsaStructInDb`. - fn salsa_struct_in_db_impl(&self) -> syn::ItemImpl { - let ident = self.id_ident(); - let jar_ty = self.jar_ty(); - parse_quote! { - impl salsa::salsa_struct::SalsaStructInDb for #ident - where - DB: ?Sized + salsa::DbWithJar<#jar_ty>, - { - fn register_dependent_fn(_db: &DB, _index: salsa::routes::IngredientIndex) { - // Do nothing here, at least for now. - // If/when we add ability to delete inputs, this would become relevant. - } - } - } - } -} diff --git a/third-party/vendor/salsa-2022-macros/src/jar.rs b/third-party/vendor/salsa-2022-macros/src/jar.rs deleted file mode 100644 index 44b9fbdd..00000000 --- a/third-party/vendor/salsa-2022-macros/src/jar.rs +++ /dev/null @@ -1,172 +0,0 @@ -use proc_macro2::Literal; -use syn::punctuated::Punctuated; -use syn::spanned::Spanned; -use syn::{Field, FieldsUnnamed, Ident, ItemStruct, Path, Token}; - -use crate::options::Options; - -// Source: -// -// #[salsa::jar(db = Jar0Db)] -// pub struct Jar0(Entity0, Ty0, EntityComponent0, my_func); - -pub(crate) fn jar( - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - let options = syn::parse_macro_input!(args as Args); - let db_path = match options.db_path { - Some(v) => v, - None => panic!("no `db` specified"), - }; - let input = syn::parse_macro_input!(input as ItemStruct); - jar_struct_and_friends(&db_path, &input).into() -} - -type Args = Options; - -struct Jar; - -impl crate::options::AllowedOptions for Jar { - const RETURN_REF: bool = false; - - const SPECIFY: bool = false; - - const NO_EQ: bool = false; - - const SINGLETON: bool = false; - - const JAR: bool = false; - - const DATA: bool = false; - - const DB: bool = true; - - const RECOVERY_FN: bool = false; - - const LRU: bool = false; - - const CONSTRUCTOR_NAME: bool = false; -} - -pub(crate) fn jar_struct_and_friends( - jar_trait: &Path, - input: &ItemStruct, -) -> proc_macro2::TokenStream { - let output_struct = jar_struct(input); - - let jar_struct = &input.ident; - - // for each field, we need to generate an impl of `HasIngredientsFor` - let has_ingredients_for_impls: Vec<_> = input - .fields - .iter() - .zip(0..) - .map(|(field, index)| has_ingredients_for_impl(jar_struct, field, index)) - .collect(); - - let jar_impl = jar_impl(jar_struct, jar_trait, input); - - quote! { - #output_struct - - #(#has_ingredients_for_impls)* - - #jar_impl - } -} - -pub(crate) fn has_ingredients_for_impl( - jar_struct: &Ident, - field: &Field, - index: u32, -) -> proc_macro2::TokenStream { - let field_ty = &field.ty; - let index = Literal::u32_unsuffixed(index); - quote! { - impl salsa::storage::HasIngredientsFor<#field_ty> for #jar_struct { - fn ingredient(&self) -> &<#field_ty as salsa::storage::IngredientsFor>::Ingredients { - &self.#index - } - - fn ingredient_mut(&mut self) -> &mut <#field_ty as salsa::storage::IngredientsFor>::Ingredients { - &mut self.#index - } - } - } -} - -pub(crate) fn jar_impl( - jar_struct: &Ident, - jar_trait: &Path, - input: &ItemStruct, -) -> proc_macro2::TokenStream { - let field_tys: Vec<_> = input.fields.iter().map(|f| &f.ty).collect(); - let field_var_names: &Vec<_> = &input - .fields - .iter() - .zip(0..) - .map(|(f, i)| syn::LitInt::new(&format!("{}", i), f.ty.span())) - .collect(); - // ANCHOR: init_jar - quote! { - unsafe impl<'salsa_db> salsa::jar::Jar<'salsa_db> for #jar_struct { - type DynDb = dyn #jar_trait + 'salsa_db; - - unsafe fn init_jar(place: *mut Self, routes: &mut salsa::routes::Routes) - where - DB: salsa::storage::JarFromJars + salsa::storage::DbWithJar, - { - #( - unsafe { - std::ptr::addr_of_mut!((*place).#field_var_names) - .write(<#field_tys as salsa::storage::IngredientsFor>::create_ingredients(routes)); - } - )* - } - } - } - // ANCHOR_END: init_jar -} - -pub(crate) fn jar_struct(input: &ItemStruct) -> ItemStruct { - let mut output_struct = input.clone(); - output_struct.fields = generate_fields(input).into(); - if output_struct.semi_token.is_none() { - output_struct.semi_token = Some(Token![;](input.struct_token.span)); - } - output_struct -} - -fn generate_fields(input: &ItemStruct) -> FieldsUnnamed { - // Generate the - let mut output_fields = Punctuated::new(); - for field in input.fields.iter() { - let mut field = field.clone(); - - // Convert to anonymous fields - field.ident = None; - - let field_ty = &field.ty; - field.ty = - syn::parse2(quote!(< #field_ty as salsa::storage::IngredientsFor >::Ingredients)) - .unwrap(); - - output_fields.push(field); - } - - let paren_token = match &input.fields { - syn::Fields::Named(f) => syn::token::Paren { - span: f.brace_token.span, - }, - syn::Fields::Unnamed(f) => f.paren_token, - syn::Fields::Unit => syn::token::Paren { - span: input.ident.span(), - }, - }; - - FieldsUnnamed { - paren_token, - unnamed: output_fields, - } -} diff --git a/third-party/vendor/salsa-2022-macros/src/lib.rs b/third-party/vendor/salsa-2022-macros/src/lib.rs deleted file mode 100644 index 45b31e67..00000000 --- a/third-party/vendor/salsa-2022-macros/src/lib.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! This crate provides salsa's macros and attributes. - -#![recursion_limit = "256"] - -extern crate proc_macro; -extern crate proc_macro2; -#[macro_use] -extern crate quote; - -use proc_macro::TokenStream; - -macro_rules! parse_quote { - ($($inp:tt)*) => { - syn::parse2(quote!{$($inp)*}).unwrap_or_else(|err| { - panic!("failed to parse at {}:{}:{}: {}", file!(), line!(), column!(), err) - }) - } -} - -macro_rules! parse_quote_spanned { - ($($inp:tt)*) => { - syn::parse2(quote_spanned!{$($inp)*}).unwrap_or_else(|err| { - panic!("failed to parse at {}:{}:{}: {}", file!(), line!(), column!(), err) - }) - } -} - -/// Convert a single Ident to Literal: useful when &'static str is needed. -pub(crate) fn literal(ident: &proc_macro2::Ident) -> proc_macro2::Literal { - proc_macro2::Literal::string(&ident.to_string()) -} - -mod accumulator; -mod configuration; -mod db; -mod input; -mod interned; -mod jar; -mod options; -mod salsa_struct; -mod tracked; -mod tracked_fn; -mod tracked_struct; - -#[proc_macro_attribute] -pub fn accumulator(args: TokenStream, input: TokenStream) -> TokenStream { - accumulator::accumulator(args, input) -} - -#[proc_macro_attribute] -pub fn jar(args: TokenStream, input: TokenStream) -> TokenStream { - jar::jar(args, input) -} - -#[proc_macro_attribute] -pub fn db(args: TokenStream, input: TokenStream) -> TokenStream { - db::db(args, input) -} - -#[proc_macro_attribute] -pub fn interned(args: TokenStream, input: TokenStream) -> TokenStream { - interned::interned(args, input) -} - -#[proc_macro_attribute] -pub fn input(args: TokenStream, input: TokenStream) -> TokenStream { - input::input(args, input) -} - -#[proc_macro_attribute] -pub fn tracked(args: TokenStream, input: TokenStream) -> TokenStream { - tracked::tracked(args, input) -} diff --git a/third-party/vendor/salsa-2022-macros/src/options.rs b/third-party/vendor/salsa-2022-macros/src/options.rs deleted file mode 100644 index 38a8fb7e..00000000 --- a/third-party/vendor/salsa-2022-macros/src/options.rs +++ /dev/null @@ -1,280 +0,0 @@ -use std::marker::PhantomData; - -use syn::{ext::IdentExt, spanned::Spanned}; - -/// "Options" are flags that can be supplied to the various salsa related -/// macros. They are listed like `(ref, no_eq, foo=bar)` etc. The commas -/// are required and trailing commas are permitted. The options accepted -/// for any particular location are configured via the `AllowedOptions` -/// trait. -pub(crate) struct Options { - /// The `return_ref` option is used to signal that field/return type is "by ref" - /// - /// If this is `Some`, the value is the `ref` identifier. - pub return_ref: Option, - - /// The `no_eq` option is used to signal that a given field does not implement - /// the `Eq` trait and cannot be compared for equality. - /// - /// If this is `Some`, the value is the `no_eq` identifier. - pub no_eq: Option, - - /// The `singleton` option is used on input with only one field - /// It allows the creation of convenient methods - pub singleton: Option, - - /// The `specify` option is used to signal that a tracked function can - /// have its value externally specified (at least some of the time). - /// - /// If this is `Some`, the value is the `specify` identifier. - pub specify: Option, - - /// The `jar = ` option is used to indicate the jar; it defaults to `crate::jar`. - /// - /// If this is `Some`, the value is the ``. - pub jar_ty: Option, - - /// The `db = ` option is used to indicate the db. - /// - /// If this is `Some`, the value is the ``. - pub db_path: Option, - - /// The `recovery_fn = ` option is used to indicate the recovery function. - /// - /// If this is `Some`, the value is the ``. - pub recovery_fn: Option, - - /// The `data = ` option is used to define the name of the data type for an interned - /// struct. - /// - /// If this is `Some`, the value is the ``. - pub data: Option, - - /// The `lru = ` option is used to set the lru capacity for a tracked function. - /// - /// If this is `Some`, the value is the ``. - pub lru: Option, - - /// The `constructor = ` option lets the user specify the name of - /// the constructor of a salsa struct. - /// - /// If this is `Some`, the value is the ``. - pub constructor_name: Option, - - /// Remember the `A` parameter, which plays no role after parsing. - phantom: PhantomData, -} - -impl Default for Options { - fn default() -> Self { - Self { - return_ref: Default::default(), - specify: Default::default(), - no_eq: Default::default(), - jar_ty: Default::default(), - db_path: Default::default(), - recovery_fn: Default::default(), - data: Default::default(), - constructor_name: Default::default(), - phantom: Default::default(), - lru: Default::default(), - singleton: Default::default(), - } - } -} - -/// These flags determine which options are allowed in a given context -pub(crate) trait AllowedOptions { - const RETURN_REF: bool; - const SPECIFY: bool; - const NO_EQ: bool; - const SINGLETON: bool; - const JAR: bool; - const DATA: bool; - const DB: bool; - const RECOVERY_FN: bool; - const LRU: bool; - const CONSTRUCTOR_NAME: bool; -} - -type Equals = syn::Token![=]; -type Comma = syn::Token![,]; - -impl Options { - /// Returns the `jar type` given by the user; if none is given, - /// returns the default `crate::Jar`. - pub(crate) fn jar_ty(&self) -> syn::Type { - if let Some(jar_ty) = &self.jar_ty { - return jar_ty.clone(); - } - - parse_quote! {crate::Jar} - } - - pub(crate) fn should_backdate(&self) -> bool { - self.no_eq.is_none() - } -} - -impl syn::parse::Parse for Options { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let mut options = Options::default(); - - while !input.is_empty() { - let ident: syn::Ident = syn::Ident::parse_any(input)?; - if ident == "return_ref" { - if A::RETURN_REF { - if let Some(old) = std::mem::replace(&mut options.return_ref, Some(ident)) { - return Err(syn::Error::new( - old.span(), - "option `return_ref` provided twice", - )); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`return_ref` option not allowed here", - )); - } - } else if ident == "no_eq" { - if A::NO_EQ { - if let Some(old) = std::mem::replace(&mut options.no_eq, Some(ident)) { - return Err(syn::Error::new(old.span(), "option `no_eq` provided twice")); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`no_eq` option not allowed here", - )); - } - } else if ident == "singleton" { - if A::SINGLETON { - if let Some(old) = std::mem::replace(&mut options.singleton, Some(ident)) { - return Err(syn::Error::new( - old.span(), - "option `singleton` provided twice", - )); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`singleton` option not allowed here", - )); - } - } else if ident == "specify" { - if A::SPECIFY { - if let Some(old) = std::mem::replace(&mut options.specify, Some(ident)) { - return Err(syn::Error::new( - old.span(), - "option `specify` provided twice", - )); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`specify` option not allowed here", - )); - } - } else if ident == "jar" { - if A::JAR { - let _eq = Equals::parse(input)?; - let ty = syn::Type::parse(input)?; - if let Some(old) = std::mem::replace(&mut options.jar_ty, Some(ty)) { - return Err(syn::Error::new(old.span(), "option `jar` provided twice")); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`jar` option not allowed here", - )); - } - } else if ident == "db" { - if A::DB { - let _eq = Equals::parse(input)?; - let path = syn::Path::parse(input)?; - if let Some(old) = std::mem::replace(&mut options.db_path, Some(path)) { - return Err(syn::Error::new(old.span(), "option `db` provided twice")); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`db` option not allowed here", - )); - } - } else if ident == "recovery_fn" { - if A::RECOVERY_FN { - let _eq = Equals::parse(input)?; - let path = syn::Path::parse(input)?; - if let Some(old) = std::mem::replace(&mut options.recovery_fn, Some(path)) { - return Err(syn::Error::new( - old.span(), - "option `recovery_fn` provided twice", - )); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`recovery_fn` option not allowed here", - )); - } - } else if ident == "data" { - if A::DATA { - let _eq = Equals::parse(input)?; - let ident = syn::Ident::parse(input)?; - if let Some(old) = std::mem::replace(&mut options.data, Some(ident)) { - return Err(syn::Error::new(old.span(), "option `data` provided twice")); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`data` option not allowed here", - )); - } - } else if ident == "lru" { - if A::LRU { - let _eq = Equals::parse(input)?; - let lit = syn::LitInt::parse(input)?; - let value = lit.base10_parse::()?; - if let Some(old) = std::mem::replace(&mut options.lru, Some(value)) { - return Err(syn::Error::new(old.span(), "option `lru` provided twice")); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`lru` option not allowed here", - )); - } - } else if ident == "constructor" { - if A::CONSTRUCTOR_NAME { - let _eq = Equals::parse(input)?; - let ident = syn::Ident::parse(input)?; - if let Some(old) = std::mem::replace(&mut options.constructor_name, Some(ident)) - { - return Err(syn::Error::new( - old.span(), - "option `constructor` provided twice", - )); - } - } else { - return Err(syn::Error::new( - ident.span(), - "`constructor` option not allowed here", - )); - } - } else { - return Err(syn::Error::new( - ident.span(), - format!("unrecognized option `{}`", ident), - )); - } - - if input.is_empty() { - break; - } - - let _comma = Comma::parse(input)?; - } - - Ok(options) - } -} diff --git a/third-party/vendor/salsa-2022-macros/src/salsa_struct.rs b/third-party/vendor/salsa-2022-macros/src/salsa_struct.rs deleted file mode 100644 index 3c3378b6..00000000 --- a/third-party/vendor/salsa-2022-macros/src/salsa_struct.rs +++ /dev/null @@ -1,472 +0,0 @@ -//! Common code for `#[salsa::interned]`, `#[salsa::input]`, and -//! `#[salsa::tracked]` decorators. -//! -//! Example of usage: -//! -//! ```rust,ignore -//! #[salsa::interned(jar = Jar0, data = TyData0)] -//! #[derive(Eq, PartialEq, Hash, Debug, Clone)] -//! struct Ty0 { -//! field1: Type1, -//! #[ref] field2: Type2, -//! ... -//! } -//! ``` -//! For an interned or entity struct `Foo`, we generate: -//! -//! * the actual struct: `struct Foo(Id);` -//! * constructor function: `impl Foo { fn new(db: &crate::Db, field1: Type1, ..., fieldN: TypeN) -> Self { ... } } -//! * field accessors: `impl Foo { fn field1(&self) -> Type1 { self.field1.clone() } }` -//! * if the field is `ref`, we generate `fn field1(&self) -> &Type1` -//! -//! Only if there are no `ref` fields: -//! -//! * the data type: `struct FooData { field1: Type1, ... }` or `enum FooData { ... }` -//! * data method `impl Foo { fn data(&self, db: &dyn crate::Db) -> FooData { FooData { f: self.f(db), ... } } }` -//! * this could be optimized, particularly for interned fields - -use crate::{ - configuration, - options::{AllowedOptions, Options}, -}; -use heck::ToUpperCamelCase; -use proc_macro2::{Ident, Literal, Span, TokenStream}; -use syn::spanned::Spanned; - -pub(crate) enum SalsaStructKind { - Input, - Tracked, - Interned, -} - -pub(crate) struct SalsaStruct { - kind: SalsaStructKind, - args: Options, - struct_item: syn::ItemStruct, - fields: Vec, -} - -const BANNED_FIELD_NAMES: &[&str] = &["from", "new"]; - -impl SalsaStruct { - pub(crate) fn new( - kind: SalsaStructKind, - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, - ) -> syn::Result { - let struct_item = syn::parse(input)?; - Self::with_struct(kind, args, struct_item) - } - - pub(crate) fn with_struct( - kind: SalsaStructKind, - args: proc_macro::TokenStream, - struct_item: syn::ItemStruct, - ) -> syn::Result { - let args: Options = syn::parse(args)?; - let fields = Self::extract_options(&struct_item)?; - Ok(Self { - kind, - args, - struct_item, - fields, - }) - } - - /// Extract out the fields and their options: - /// If this is a struct, it must use named fields, so we can define field accessors. - /// If it is an enum, then this is not necessary. - pub(crate) fn extract_options(struct_item: &syn::ItemStruct) -> syn::Result> { - match &struct_item.fields { - syn::Fields::Named(n) => Ok(n - .named - .iter() - .map(SalsaField::new) - .collect::>>()?), - f => Err(syn::Error::new_spanned( - f, - "must have named fields for a struct", - )), - } - } - - /// Iterator over all named fields. - /// - /// If this is an enum, empty iterator. - pub(crate) fn all_fields(&self) -> impl Iterator { - self.fields.iter() - } - - pub(crate) fn is_identity_field(&self, field: &SalsaField) -> bool { - match self.kind { - SalsaStructKind::Input | SalsaStructKind::Tracked => field.has_id_attr, - SalsaStructKind::Interned => true, - } - } - - /// Names of all fields (id and value). - /// - /// If this is an enum, empty vec. - pub(crate) fn all_field_names(&self) -> Vec<&syn::Ident> { - self.all_fields().map(|ef| ef.name()).collect() - } - - /// Visibilities of all fields - pub(crate) fn all_field_vises(&self) -> Vec<&syn::Visibility> { - self.all_fields().map(|ef| ef.vis()).collect() - } - - /// Names of getters of all fields - pub(crate) fn all_get_field_names(&self) -> Vec<&syn::Ident> { - self.all_fields().map(|ef| ef.get_name()).collect() - } - - /// Types of all fields (id and value). - /// - /// If this is an enum, empty vec. - pub(crate) fn all_field_tys(&self) -> Vec<&syn::Type> { - self.all_fields().map(|ef| ef.ty()).collect() - } - - /// The name of the "identity" struct (this is the name the user gave, e.g., `Foo`). - pub(crate) fn id_ident(&self) -> &syn::Ident { - &self.struct_item.ident - } - - /// Type of the jar for this struct - pub(crate) fn jar_ty(&self) -> syn::Type { - self.args.jar_ty() - } - - /// checks if the "singleton" flag was set - pub(crate) fn is_isingleton(&self) -> bool { - self.args.singleton.is_some() - } - - pub(crate) fn db_dyn_ty(&self) -> syn::Type { - let jar_ty = self.jar_ty(); - parse_quote! { - <#jar_ty as salsa::jar::Jar<'_>>::DynDb - } - } - - /// The name of the "data" struct (this comes from the `data = Foo` option or, - /// if that is not provided, by concatenating `Data` to the name of the struct). - pub(crate) fn data_ident(&self) -> syn::Ident { - match &self.args.data { - Some(d) => d.clone(), - None => syn::Ident::new( - &format!("__{}Data", self.id_ident()), - self.id_ident().span(), - ), - } - } - - /// Generate `struct Foo(Id)` - pub(crate) fn id_struct(&self) -> syn::ItemStruct { - let ident = self.id_ident(); - let visibility = &self.struct_item.vis; - - // Extract the attributes the user gave, but screen out derive, since we are adding our own. - let attrs: Vec<_> = self - .struct_item - .attrs - .iter() - .filter(|attr| !attr.path.is_ident("derive")) - .collect(); - - parse_quote! { - #(#attrs)* - #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] - #visibility struct #ident(salsa::Id); - } - } - - /// Generates the `struct FooData` struct (or enum). - /// This type inherits all the attributes written by the user. - /// - /// When using named fields, we synthesize the struct and field names. - /// - /// When no named fields are available, copy the existing type. - pub(crate) fn data_struct(&self) -> syn::ItemStruct { - let ident = self.data_ident(); - let visibility = self.visibility(); - let all_field_names = self.all_field_names(); - let all_field_tys = self.all_field_tys(); - parse_quote! { - /// Internal struct used for interned item - #[derive(Eq, PartialEq, Hash, Clone)] - #visibility struct #ident { - #( - #all_field_names: #all_field_tys, - )* - } - } - } - - /// Returns the visibility of this item - pub(crate) fn visibility(&self) -> &syn::Visibility { - &self.struct_item.vis - } - - /// Returns the `constructor_name` in `Options` if it is `Some`, else `new` - pub(crate) fn constructor_name(&self) -> syn::Ident { - match self.args.constructor_name.clone() { - Some(name) => name, - None => Ident::new("new", Span::call_site()), - } - } - - /// For each of the fields passed as an argument, - /// generate a struct named `Ident_Field` and an impl - /// of `salsa::function::Configuration` for that struct. - pub(crate) fn field_config_structs_and_impls<'a>( - &self, - fields: impl Iterator, - ) -> (Vec, Vec) { - let ident = &self.id_ident(); - let jar_ty = self.jar_ty(); - let visibility = self.visibility(); - fields - .map(|ef| { - let value_field_name = ef.name(); - let value_field_ty = ef.ty(); - let value_field_backdate = ef.is_backdate_field(); - let config_name = syn::Ident::new( - &format!( - "__{}", - format!("{}_{}", ident, value_field_name).to_upper_camel_case() - ), - value_field_name.span(), - ); - let item_struct: syn::ItemStruct = parse_quote! { - #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] - #visibility struct #config_name(std::convert::Infallible); - }; - - let execute_string = Literal::string(&format!("`execute` method for field `{}::{}` invoked", - ident, - ef.name(), - )); - - let recover_from_cycle_string = Literal::string(&format!("`execute` method for field `{}::{}` invoked", - ident, - ef.name(), - )); - - let should_backdate_value_fn = configuration::should_backdate_value_fn(value_field_backdate); - let item_impl: syn::ItemImpl = parse_quote! { - impl salsa::function::Configuration for #config_name { - type Jar = #jar_ty; - type SalsaStruct = #ident; - type Key = #ident; - type Value = #value_field_ty; - const CYCLE_STRATEGY: salsa::cycle::CycleRecoveryStrategy = salsa::cycle::CycleRecoveryStrategy::Panic; - - #should_backdate_value_fn - - fn execute(db: &salsa::function::DynDb, key: Self::Key) -> Self::Value { - panic!(#execute_string) - } - - fn recover_from_cycle(db: &salsa::function::DynDb, cycle: &salsa::Cycle, key: Self::Key) -> Self::Value { - panic!(#recover_from_cycle_string) - } - } - }; - - (item_struct, item_impl) - }) - .unzip() - } - - /// Generate `impl salsa::AsId for Foo` - pub(crate) fn as_id_impl(&self) -> syn::ItemImpl { - let ident = self.id_ident(); - parse_quote! { - impl salsa::AsId for #ident { - fn as_id(self) -> salsa::Id { - self.0 - } - - fn from_id(id: salsa::Id) -> Self { - #ident(id) - } - } - - } - } - - /// Generate `impl salsa::DebugWithDb for Foo` - pub(crate) fn as_debug_with_db_impl(&self) -> syn::ItemImpl { - let ident = self.id_ident(); - - let db_type = self.db_dyn_ty(); - let ident_string = ident.to_string(); - - // `::salsa::debug::helper::SalsaDebug` will use `DebugWithDb` or fallbak to `Debug` - let fields = self - .all_fields() - .into_iter() - .map(|field| -> TokenStream { - let field_name_string = field.name().to_string(); - let field_getter = field.get_name(); - let field_ty = field.ty(); - - let field_debug = quote_spanned! { field.field.span() => - debug_struct = debug_struct.field( - #field_name_string, - &::salsa::debug::helper::SalsaDebug::<#field_ty, #db_type>::salsa_debug( - #[allow(clippy::needless_borrow)] - &self.#field_getter(_db), - _db, - _include_all_fields - ) - ); - }; - - if self.is_identity_field(field) { - quote_spanned! { field.field.span() => - #field_debug - } - } else { - quote_spanned! { field.field.span() => - if _include_all_fields { - #field_debug - } - } - } - }) - .collect::(); - - // `use ::salsa::debug::helper::Fallback` is needed for the fallback to `Debug` impl - parse_quote_spanned! {ident.span()=> - impl ::salsa::DebugWithDb<#db_type> for #ident { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>, _db: &#db_type, _include_all_fields: bool) -> ::std::fmt::Result { - #[allow(unused_imports)] - use ::salsa::debug::helper::Fallback; - let mut debug_struct = &mut f.debug_struct(#ident_string); - debug_struct = debug_struct.field("[salsa id]", &self.0.as_u32()); - #fields - debug_struct.finish() - } - } - } - } - - /// Disallow `#[id]` attributes on the fields of this struct. - /// - /// If an `#[id]` field is found, return an error. - /// - /// # Parameters - /// - /// * `kind`, the attribute name (e.g., `input` or `interned`) - pub(crate) fn disallow_id_fields(&self, kind: &str) -> syn::Result<()> { - for ef in self.all_fields() { - if ef.has_id_attr { - return Err(syn::Error::new( - ef.name().span(), - format!("`#[id]` cannot be used with `#[salsa::{kind}]`"), - )); - } - } - - Ok(()) - } -} - -#[allow(clippy::type_complexity)] -pub(crate) const FIELD_OPTION_ATTRIBUTES: &[(&str, fn(&syn::Attribute, &mut SalsaField))] = &[ - ("id", |_, ef| ef.has_id_attr = true), - ("return_ref", |_, ef| ef.has_ref_attr = true), - ("no_eq", |_, ef| ef.has_no_eq_attr = true), - ("get", |attr, ef| { - ef.get_name = attr.parse_args().unwrap(); - }), - ("set", |attr, ef| { - ef.set_name = attr.parse_args().unwrap(); - }), -]; - -pub(crate) struct SalsaField { - field: syn::Field, - - pub(crate) has_id_attr: bool, - pub(crate) has_ref_attr: bool, - pub(crate) has_no_eq_attr: bool, - get_name: syn::Ident, - set_name: syn::Ident, -} - -impl SalsaField { - pub(crate) fn new(field: &syn::Field) -> syn::Result { - let field_name = field.ident.as_ref().unwrap(); - let field_name_str = field_name.to_string(); - if BANNED_FIELD_NAMES.iter().any(|n| *n == field_name_str) { - return Err(syn::Error::new( - field_name.span(), - &format!( - "the field name `{}` is disallowed in salsa structs", - field_name_str - ), - )); - } - - let get_name = Ident::new(&field_name_str, Span::call_site()); - let set_name = Ident::new(&format!("set_{}", field_name_str), Span::call_site()); - let mut result = SalsaField { - field: field.clone(), - has_id_attr: false, - has_ref_attr: false, - has_no_eq_attr: false, - get_name, - set_name, - }; - - // Scan the attributes and look for the salsa attributes: - for attr in &field.attrs { - for (fa, func) in FIELD_OPTION_ATTRIBUTES { - if attr.path.is_ident(fa) { - func(attr, &mut result); - } - } - } - - Ok(result) - } - - /// The name of this field (all `SalsaField` instances are named). - pub(crate) fn name(&self) -> &syn::Ident { - self.field.ident.as_ref().unwrap() - } - - /// The visibility of this field. - pub(crate) fn vis(&self) -> &syn::Visibility { - &self.field.vis - } - - /// The type of this field (all `SalsaField` instances are named). - pub(crate) fn ty(&self) -> &syn::Type { - &self.field.ty - } - - /// The name of this field's get method - pub(crate) fn get_name(&self) -> &syn::Ident { - &self.get_name - } - - /// The name of this field's get method - pub(crate) fn set_name(&self) -> &syn::Ident { - &self.set_name - } - - /// Do you clone the value of this field? (True if it is not a ref field) - pub(crate) fn is_clone_field(&self) -> bool { - !self.has_ref_attr - } - - /// Do you potentially backdate the value of this field? (True if it is not a no-eq field) - pub(crate) fn is_backdate_field(&self) -> bool { - !self.has_no_eq_attr - } -} diff --git a/third-party/vendor/salsa-2022-macros/src/tracked.rs b/third-party/vendor/salsa-2022-macros/src/tracked.rs deleted file mode 100644 index 6417a894..00000000 --- a/third-party/vendor/salsa-2022-macros/src/tracked.rs +++ /dev/null @@ -1,21 +0,0 @@ -use syn::{spanned::Spanned, Item}; - -pub(crate) fn tracked( - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - let item = syn::parse_macro_input!(input as Item); - let res = match item { - syn::Item::Struct(item) => crate::tracked_struct::tracked(args, item), - syn::Item::Fn(item) => crate::tracked_fn::tracked_fn(args, item), - syn::Item::Impl(item) => crate::tracked_fn::tracked_impl(args, item), - _ => Err(syn::Error::new( - item.span(), - "tracked can only be applied to structs, functions, and impls", - )), - }; - match res { - Ok(s) => s.into(), - Err(err) => err.into_compile_error().into(), - } -} diff --git a/third-party/vendor/salsa-2022-macros/src/tracked_fn.rs b/third-party/vendor/salsa-2022-macros/src/tracked_fn.rs deleted file mode 100644 index b15d6ae6..00000000 --- a/third-party/vendor/salsa-2022-macros/src/tracked_fn.rs +++ /dev/null @@ -1,893 +0,0 @@ -use proc_macro2::{Literal, TokenStream}; -use syn::spanned::Spanned; -use syn::visit_mut::VisitMut; -use syn::{ReturnType, Token}; - -use crate::configuration::{self, Configuration, CycleRecoveryStrategy}; -use crate::options::Options; - -pub(crate) fn tracked_fn( - args: proc_macro::TokenStream, - mut item_fn: syn::ItemFn, -) -> syn::Result { - let args: FnArgs = syn::parse(args)?; - if item_fn.sig.inputs.is_empty() { - return Err(syn::Error::new( - item_fn.sig.ident.span(), - "tracked functions must have at least a database argument", - )); - } - - if let syn::FnArg::Receiver(receiver) = &item_fn.sig.inputs[0] { - return Err(syn::Error::new( - receiver.span(), - "#[salsa::tracked] must also be applied to the impl block for tracked methods", - )); - } - - if let Some(s) = &args.specify { - if function_type(&item_fn) == FunctionType::RequiresInterning { - return Err(syn::Error::new( - s.span(), - "tracked function takes too many arguments to have its value set with `specify`", - )); - } - - if args.lru.is_some() { - return Err(syn::Error::new( - s.span(), - "`specify` and `lru` cannot be used together", - )); - } - } - - let (config_ty, fn_struct) = fn_struct(&args, &item_fn)?; - *item_fn.block = getter_fn(&args, &mut item_fn.sig, item_fn.block.span(), &config_ty)?; - - Ok(quote! { - #fn_struct - - // we generate a `'db` lifetime that clippy - // sometimes doesn't like - #[allow(clippy::needless_lifetimes)] - #item_fn - }) -} - -type FnArgs = Options; - -struct TrackedFn; - -impl crate::options::AllowedOptions for TrackedFn { - const RETURN_REF: bool = true; - - const SPECIFY: bool = true; - - const NO_EQ: bool = true; - - const SINGLETON: bool = false; - - const JAR: bool = true; - - const DATA: bool = false; - - const DB: bool = false; - - const RECOVERY_FN: bool = true; - - const LRU: bool = true; - - const CONSTRUCTOR_NAME: bool = false; -} - -type ImplArgs = Options; - -pub(crate) fn tracked_impl( - args: proc_macro::TokenStream, - mut item_impl: syn::ItemImpl, -) -> syn::Result { - let args: ImplArgs = syn::parse(args)?; - let self_type = match &*item_impl.self_ty { - syn::Type::Path(path) => path, - _ => { - return Err(syn::Error::new( - item_impl.self_ty.span(), - "#[salsa::tracked] can only be applied to salsa structs", - )) - } - }; - let self_type_name = &self_type.path.segments.last().unwrap().ident; - let name_prefix = match &item_impl.trait_ { - Some((_, trait_name, _)) => format!( - "{}_{}", - self_type_name, - trait_name.segments.last().unwrap().ident - ), - None => format!("{}", self_type_name), - }; - let extra_impls = item_impl - .items - .iter_mut() - .filter_map(|item| { - let item_method = match item { - syn::ImplItem::Method(item_method) => item_method, - _ => return None, - }; - let salsa_tracked_attr = item_method.attrs.iter().position(|attr| { - let path = &attr.path.segments; - path.len() == 2 - && path[0].arguments == syn::PathArguments::None - && path[0].ident == "salsa" - && path[1].arguments == syn::PathArguments::None - && path[1].ident == "tracked" - })?; - let salsa_tracked_attr = item_method.attrs.remove(salsa_tracked_attr); - let inner_args = if !salsa_tracked_attr.tokens.is_empty() { - salsa_tracked_attr.parse_args() - } else { - Ok(FnArgs::default()) - }; - let inner_args = match inner_args { - Ok(inner_args) => inner_args, - Err(err) => return Some(Err(err)), - }; - let name = format!("{}_{}", name_prefix, item_method.sig.ident); - Some(tracked_method( - &args, - inner_args, - item_method, - self_type, - &name, - )) - }) - // Collate all the errors so we can display them all at once - .fold(Ok(Vec::new()), |mut acc, res| { - match (&mut acc, res) { - (Ok(extra_impls), Ok(impls)) => extra_impls.push(impls), - (Ok(_), Err(err)) => acc = Err(err), - (Err(_), Ok(_)) => {} - (Err(errors), Err(err)) => errors.combine(err), - } - acc - })?; - - Ok(quote! { - #item_impl - - #(#extra_impls)* - }) -} - -struct TrackedImpl; - -impl crate::options::AllowedOptions for TrackedImpl { - const RETURN_REF: bool = false; - - const SPECIFY: bool = false; - - const NO_EQ: bool = false; - - const JAR: bool = true; - - const DATA: bool = false; - - const DB: bool = false; - - const RECOVERY_FN: bool = false; - - const LRU: bool = false; - - const CONSTRUCTOR_NAME: bool = false; - - const SINGLETON: bool = false; -} - -fn tracked_method( - outer_args: &ImplArgs, - mut args: FnArgs, - item_method: &mut syn::ImplItemMethod, - self_type: &syn::TypePath, - name: &str, -) -> syn::Result { - args.jar_ty = args.jar_ty.or_else(|| outer_args.jar_ty.clone()); - - if item_method.sig.inputs.len() <= 1 { - return Err(syn::Error::new( - item_method.sig.ident.span(), - "tracked methods must have at least self and a database argument", - )); - } - - let mut item_fn = syn::ItemFn { - attrs: item_method.attrs.clone(), - vis: item_method.vis.clone(), - sig: item_method.sig.clone(), - block: Box::new(rename_self_in_block(item_method.block.clone())?), - }; - item_fn.sig.ident = syn::Ident::new(name, item_fn.sig.ident.span()); - // Flip the first and second arguments as the rest of the code expects the - // database to come first and the struct to come second. We also need to - // change the self argument to a normal typed argument called __salsa_self. - let mut original_inputs = item_fn.sig.inputs.into_pairs(); - let self_param = match original_inputs.next().unwrap().into_value() { - syn::FnArg::Receiver(r) if r.reference.is_none() => r, - arg => return Err(syn::Error::new(arg.span(), "first argument must be self")), - }; - let db_param = original_inputs.next().unwrap().into_value(); - let mut inputs = syn::punctuated::Punctuated::new(); - inputs.push(db_param); - inputs.push(syn::FnArg::Typed(syn::PatType { - attrs: self_param.attrs, - pat: Box::new(syn::Pat::Ident(syn::PatIdent { - attrs: Vec::new(), - by_ref: None, - mutability: self_param.mutability, - ident: syn::Ident::new("__salsa_self", self_param.self_token.span), - subpat: None, - })), - colon_token: Default::default(), - ty: Box::new(syn::Type::Path(self_type.clone())), - })); - inputs.push_punct(Default::default()); - inputs.extend(original_inputs); - item_fn.sig.inputs = inputs; - - let (config_ty, fn_struct) = crate::tracked_fn::fn_struct(&args, &item_fn)?; - - // we generate a `'db` lifetime that clippy - // sometimes doesn't like - item_method - .attrs - .push(syn::parse_quote! {#[allow(clippy::needless_lifetimes)]}); - - item_method.block = getter_fn( - &args, - &mut item_method.sig, - item_method.block.span(), - &config_ty, - )?; - - Ok(fn_struct) -} - -/// Rename all occurrences of `self` to `__salsa_self` in a block -/// so that it can be used in a free function. -fn rename_self_in_block(mut block: syn::Block) -> syn::Result { - struct RenameIdent(syn::Result<()>); - - impl syn::visit_mut::VisitMut for RenameIdent { - fn visit_ident_mut(&mut self, i: &mut syn::Ident) { - if i == "__salsa_self" { - let err = syn::Error::new( - i.span(), - "Existing variable name clashes with 'self' -> '__salsa_self' renaming", - ); - match &mut self.0 { - Ok(()) => self.0 = Err(err), - Err(errors) => errors.combine(err), - } - } - if i == "self" { - *i = syn::Ident::new("__salsa_self", i.span()); - } - } - } - - let mut rename = RenameIdent(Ok(())); - rename.visit_block_mut(&mut block); - rename.0.map(move |()| block) -} - -/// Create the struct representing the function and all of its impls. -/// -/// This returns the name of the constructed type and the code defining everything. -fn fn_struct(args: &FnArgs, item_fn: &syn::ItemFn) -> syn::Result<(syn::Type, TokenStream)> { - let struct_item = configuration_struct(item_fn); - let configuration = fn_configuration(args, item_fn); - let struct_item_ident = &struct_item.ident; - let config_ty: syn::Type = parse_quote!(#struct_item_ident); - let configuration_impl = configuration.to_impl(&config_ty); - let ingredients_for_impl = ingredients_for_impl(args, item_fn, &config_ty); - let item_impl = setter_impl(args, item_fn, &config_ty)?; - - Ok(( - config_ty, - quote! { - #struct_item - #configuration_impl - #ingredients_for_impl - #item_impl - }, - )) -} - -/// Returns the key type for this tracked function. -/// This is a tuple of all the argument types (apart from the database). -fn key_tuple_ty(item_fn: &syn::ItemFn) -> syn::Type { - let arg_tys = item_fn.sig.inputs.iter().skip(1).map(|arg| match arg { - syn::FnArg::Receiver(_) => unreachable!(), - syn::FnArg::Typed(pat_ty) => pat_ty.ty.clone(), - }); - - parse_quote!( - (#(#arg_tys,)*) - ) -} - -fn configuration_struct(item_fn: &syn::ItemFn) -> syn::ItemStruct { - let fn_name = item_fn.sig.ident.clone(); - let visibility = &item_fn.vis; - - let salsa_struct_ty = salsa_struct_ty(item_fn); - let intern_map: syn::Type = match function_type(item_fn) { - FunctionType::Constant => { - parse_quote! { salsa::interned::IdentityInterner<()> } - } - FunctionType::SalsaStruct => { - parse_quote! { salsa::interned::IdentityInterner<#salsa_struct_ty> } - } - FunctionType::RequiresInterning => { - let key_ty = key_tuple_ty(item_fn); - parse_quote! { salsa::interned::InternedIngredient } - } - }; - - parse_quote! { - #[allow(non_camel_case_types)] - #visibility struct #fn_name { - intern_map: #intern_map, - function: salsa::function::FunctionIngredient, - } - } -} - -#[derive(Debug, PartialEq, Eq, Hash)] -enum FunctionType { - Constant, - SalsaStruct, - RequiresInterning, -} - -fn function_type(item_fn: &syn::ItemFn) -> FunctionType { - match item_fn.sig.inputs.len() { - 0 => unreachable!( - "functions have been checked to have at least a database argument by this point" - ), - 1 => FunctionType::Constant, - 2 => FunctionType::SalsaStruct, - _ => FunctionType::RequiresInterning, - } -} - -/// Every tracked fn takes a salsa struct as its second argument. -/// This fn returns the type of that second argument. -fn salsa_struct_ty(item_fn: &syn::ItemFn) -> syn::Type { - if item_fn.sig.inputs.len() == 1 { - return parse_quote! { salsa::salsa_struct::Singleton }; - } - match &item_fn.sig.inputs[1] { - syn::FnArg::Receiver(_) => panic!("receiver not expected"), - syn::FnArg::Typed(pat_ty) => (*pat_ty.ty).clone(), - } -} - -fn fn_configuration(args: &FnArgs, item_fn: &syn::ItemFn) -> Configuration { - let jar_ty = args.jar_ty(); - let salsa_struct_ty = salsa_struct_ty(item_fn); - let key_ty = match function_type(item_fn) { - FunctionType::Constant => parse_quote!(()), - FunctionType::SalsaStruct => salsa_struct_ty.clone(), - FunctionType::RequiresInterning => parse_quote!(salsa::id::Id), - }; - let value_ty = configuration::value_ty(&item_fn.sig); - - let fn_ty = item_fn.sig.ident.clone(); - - let indices = (0..item_fn.sig.inputs.len() - 1).map(Literal::usize_unsuffixed); - let (cycle_strategy, recover_fn) = if let Some(recovery_fn) = &args.recovery_fn { - // Create the `recover_from_cycle` function, which (a) maps from the interned id to the actual - // keys and then (b) invokes the recover function itself. - let cycle_strategy = CycleRecoveryStrategy::Fallback; - - let cycle_fullback = parse_quote! { - fn recover_from_cycle(__db: &salsa::function::DynDb, __cycle: &salsa::Cycle, __id: Self::Key) -> Self::Value { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = - <_ as salsa::storage::HasIngredientsFor<#fn_ty>>::ingredient(__jar); - let __key = __ingredients.intern_map.data(__runtime, __id).clone(); - #recovery_fn(__db, __cycle, #(__key.#indices),*) - } - }; - (cycle_strategy, cycle_fullback) - } else { - // When the `recovery_fn` attribute is not set, set `cycle_strategy` to `Panic` - let cycle_strategy = CycleRecoveryStrategy::Panic; - let cycle_panic = configuration::panic_cycle_recovery_fn(); - (cycle_strategy, cycle_panic) - }; - - let backdate_fn = configuration::should_backdate_value_fn(args.should_backdate()); - - // The type of the configuration struct; this has the same name as the fn itself. - - // Make a copy of the fn with a different name; we will invoke this from `execute`. - // We need to change the name because, otherwise, if the function invoked itself - // recursively it would not go through the query system. - let inner_fn_name = &syn::Ident::new("__fn", item_fn.sig.ident.span()); - let mut inner_fn = item_fn.clone(); - inner_fn.sig.ident = inner_fn_name.clone(); - - // Create the `execute` function, which (a) maps from the interned id to the actual - // keys and then (b) invokes the function itself (which we embed within). - let indices = (0..item_fn.sig.inputs.len() - 1).map(Literal::usize_unsuffixed); - let execute_fn = parse_quote! { - fn execute(__db: &salsa::function::DynDb, __id: Self::Key) -> Self::Value { - #inner_fn - - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = - <_ as salsa::storage::HasIngredientsFor<#fn_ty>>::ingredient(__jar); - let __key = __ingredients.intern_map.data(__runtime, __id).clone(); - #inner_fn_name(__db, #(__key.#indices),*) - } - }; - - Configuration { - jar_ty, - salsa_struct_ty, - key_ty, - value_ty, - cycle_strategy, - backdate_fn, - execute_fn, - recover_fn, - } -} - -fn ingredients_for_impl( - args: &FnArgs, - item_fn: &syn::ItemFn, - config_ty: &syn::Type, -) -> syn::ItemImpl { - let jar_ty = args.jar_ty(); - let debug_name = crate::literal(&item_fn.sig.ident); - - let intern_map: syn::Expr = match function_type(item_fn) { - FunctionType::Constant | FunctionType::SalsaStruct => { - parse_quote! { - salsa::interned::IdentityInterner::new() - } - } - FunctionType::RequiresInterning => { - parse_quote! { - { - let index = routes.push( - |jars| { - let jar = >::jar_from_jars(jars); - let ingredients = - <_ as salsa::storage::HasIngredientsFor>::ingredient(jar); - &ingredients.intern_map - }, - |jars| { - let jar = >::jar_from_jars_mut(jars); - let ingredients = - <_ as salsa::storage::HasIngredientsFor>::ingredient_mut(jar); - &mut ingredients.intern_map - } - ); - salsa::interned::InternedIngredient::new(index, #debug_name) - } - } - } - }; - - // set 0 as default to disable LRU - let lru = args.lru.unwrap_or(0); - - // get the name of the function as a string literal - let debug_name = crate::literal(&item_fn.sig.ident); - - parse_quote! { - impl salsa::storage::IngredientsFor for #config_ty { - type Ingredients = Self; - type Jar = #jar_ty; - - fn create_ingredients(routes: &mut salsa::routes::Routes) -> Self::Ingredients - where - DB: salsa::DbWithJar + salsa::storage::JarFromJars, - { - Self { - intern_map: #intern_map, - - function: { - let index = routes.push( - |jars| { - let jar = >::jar_from_jars(jars); - let ingredients = - <_ as salsa::storage::HasIngredientsFor>::ingredient(jar); - &ingredients.function - }, - |jars| { - let jar = >::jar_from_jars_mut(jars); - let ingredients = - <_ as salsa::storage::HasIngredientsFor>::ingredient_mut(jar); - &mut ingredients.function - }); - let ingredient = salsa::function::FunctionIngredient::new(index, #debug_name); - ingredient.set_capacity(#lru); - ingredient - } - } - } - } - } -} - -fn setter_impl( - args: &FnArgs, - item_fn: &syn::ItemFn, - config_ty: &syn::Type, -) -> syn::Result { - let ref_getter_fn = ref_getter_fn(args, item_fn, config_ty)?; - let accumulated_fn = accumulated_fn(args, item_fn, config_ty)?; - let setter_fn = setter_fn(args, item_fn, config_ty)?; - let specify_fn = specify_fn(args, item_fn, config_ty)?.map(|f| quote! { #f }); - let set_lru_fn = set_lru_capacity_fn(args, config_ty)?.map(|f| quote! { #f }); - - let setter_impl: syn::ItemImpl = parse_quote! { - impl #config_ty { - #[allow(dead_code, clippy::needless_lifetimes)] - #ref_getter_fn - - #[allow(dead_code, clippy::needless_lifetimes)] - #setter_fn - - #[allow(dead_code, clippy::needless_lifetimes)] - #accumulated_fn - - #set_lru_fn - - #specify_fn - } - }; - - Ok(setter_impl) -} - -/// Creates the shim function that looks like the original function but calls -/// into the machinery we've just generated rather than executing the code. -fn getter_fn( - args: &FnArgs, - fn_sig: &mut syn::Signature, - block_span: proc_macro2::Span, - config_ty: &syn::Type, -) -> syn::Result { - let mut is_method = false; - let mut arg_idents: Vec<_> = fn_sig - .inputs - .iter() - .map(|arg| -> syn::Result { - match arg { - syn::FnArg::Receiver(receiver) => { - is_method = true; - Ok(syn::Ident::new("self", receiver.self_token.span())) - } - syn::FnArg::Typed(pat_ty) => Ok(match &*pat_ty.pat { - syn::Pat::Ident(ident) => ident.ident.clone(), - _ => return Err(syn::Error::new(arg.span(), "unsupported argument kind")), - }), - } - }) - .collect::>()?; - // If this is a method then the order of the database and the salsa struct are reversed - // because the self argument must always come first. - if is_method { - arg_idents.swap(0, 1); - } - Ok(if args.return_ref.is_some() { - make_fn_return_ref(fn_sig)?; - parse_quote_spanned! { - block_span => { - #config_ty::get(#(#arg_idents,)*) - } - } - } else { - parse_quote_spanned! { - block_span => { - Clone::clone(#config_ty::get(#(#arg_idents,)*)) - } - } - }) -} - -/// Creates a `get` associated function that returns `&Value` -/// (to be used when `return_ref` is specified). -/// -/// (Helper for `getter_fn`) -fn ref_getter_fn( - args: &FnArgs, - item_fn: &syn::ItemFn, - config_ty: &syn::Type, -) -> syn::Result { - let jar_ty = args.jar_ty(); - let mut ref_getter_fn = item_fn.clone(); - ref_getter_fn.sig.ident = syn::Ident::new("get", item_fn.sig.ident.span()); - make_fn_return_ref(&mut ref_getter_fn.sig)?; - - let (db_var, arg_names) = fn_args(item_fn)?; - ref_getter_fn.block = parse_quote! { - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(#db_var); - let __ingredients = <_ as salsa::storage::HasIngredientsFor<#config_ty>>::ingredient(__jar); - let __key = __ingredients.intern_map.intern(__runtime, (#(#arg_names),*)); - __ingredients.function.fetch(#db_var, __key) - } - }; - - Ok(ref_getter_fn) -} - -/// Creates a `set` associated function that can be used to set (given an `&mut db`) -/// the value for this function for some inputs. -fn setter_fn( - args: &FnArgs, - item_fn: &syn::ItemFn, - config_ty: &syn::Type, -) -> syn::Result { - // The setter has *always* the same signature as the original: - // but it takes a value arg and has no return type. - let jar_ty = args.jar_ty(); - let (db_var, arg_names) = fn_args(item_fn)?; - let mut setter_sig = item_fn.sig.clone(); - let value_ty = configuration::value_ty(&item_fn.sig); - setter_sig.ident = syn::Ident::new("set", item_fn.sig.ident.span()); - match &mut setter_sig.inputs[0] { - // change from `&dyn ...` to `&mut dyn...` - syn::FnArg::Receiver(_) => unreachable!(), // early fns should have detected - syn::FnArg::Typed(pat_ty) => match &mut *pat_ty.ty { - syn::Type::Reference(ty) => { - ty.mutability = Some(Token![mut](ty.and_token.span())); - } - _ => unreachable!(), // early fns should have detected - }, - } - let value_arg = syn::Ident::new("__value", item_fn.sig.output.span()); - setter_sig.inputs.push(parse_quote!(#value_arg: #value_ty)); - setter_sig.output = ReturnType::Default; - Ok(syn::ImplItemMethod { - attrs: vec![], - vis: item_fn.vis.clone(), - defaultness: None, - sig: setter_sig, - block: parse_quote! { - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar_mut(#db_var); - let __ingredients = <_ as salsa::storage::HasIngredientsFor<#config_ty>>::ingredient_mut(__jar); - let __key = __ingredients.intern_map.intern(__runtime, (#(#arg_names),*)); - __ingredients.function.store(__runtime, __key, #value_arg, salsa::Durability::LOW) - } - }, - }) -} - -/// Create a `set_lru_capacity` associated function that can be used to change LRU -/// capacity at runtime. -/// Note that this function is only generated if the tracked function has the lru option set. -/// -/// # Examples -/// -/// ```rust,ignore -/// #[salsa::tracked(lru=32)] -/// fn my_tracked_fn(db: &dyn crate::Db, ...) { } -/// -/// my_tracked_fn::set_lru_capacity(16) -/// ``` -fn set_lru_capacity_fn( - args: &FnArgs, - config_ty: &syn::Type, -) -> syn::Result> { - if args.lru.is_none() { - return Ok(None); - } - - let jar_ty = args.jar_ty(); - let lru_fn = parse_quote! { - #[allow(dead_code, clippy::needless_lifetimes)] - fn set_lru_capacity(__db: &salsa::function::DynDb, __value: usize) { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = - <_ as salsa::storage::HasIngredientsFor<#config_ty>>::ingredient(__jar); - __ingredients.function.set_capacity(__value); - } - }; - Ok(Some(lru_fn)) -} - -fn specify_fn( - args: &FnArgs, - item_fn: &syn::ItemFn, - config_ty: &syn::Type, -) -> syn::Result> { - if args.specify.is_none() { - return Ok(None); - } - - // `specify` has the same signature as the original, - // but it takes a value arg and has no return type. - let jar_ty = args.jar_ty(); - let (db_var, arg_names) = fn_args(item_fn)?; - let mut setter_sig = item_fn.sig.clone(); - let value_ty = configuration::value_ty(&item_fn.sig); - setter_sig.ident = syn::Ident::new("specify", item_fn.sig.ident.span()); - let value_arg = syn::Ident::new("__value", item_fn.sig.output.span()); - setter_sig.inputs.push(parse_quote!(#value_arg: #value_ty)); - setter_sig.output = ReturnType::Default; - Ok(Some(syn::ImplItemMethod { - attrs: vec![], - vis: item_fn.vis.clone(), - defaultness: None, - sig: setter_sig, - block: parse_quote! { - { - - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(#db_var); - let __ingredients = <_ as salsa::storage::HasIngredientsFor<#config_ty>>::ingredient(__jar); - __ingredients.function.specify_and_record(#db_var, #(#arg_names,)* #value_arg) - } - }, - })) -} -/// Given a function def tagged with `#[return_ref]`, modifies `fn_sig` so that -/// it returns an `&Value` instead of `Value`. May introduce a name for the -/// database lifetime if required. -fn make_fn_return_ref(fn_sig: &mut syn::Signature) -> syn::Result<()> { - // An input should be a `&dyn Db`. - // We need to ensure it has a named lifetime parameter. - let (db_lifetime, _) = db_lifetime_and_ty(fn_sig)?; - - let (right_arrow, elem) = match fn_sig.output.clone() { - ReturnType::Default => (syn::Token![->](fn_sig.paren_token.span), parse_quote!(())), - ReturnType::Type(rarrow, ty) => (rarrow, ty), - }; - - let ref_output = syn::TypeReference { - and_token: syn::Token![&](right_arrow.span()), - lifetime: Some(db_lifetime), - mutability: None, - elem, - }; - - fn_sig.output = syn::ReturnType::Type(right_arrow, Box::new(ref_output.into())); - - Ok(()) -} - -/// Given a function signature, identifies the name given to the `&dyn Db` reference -/// and returns it, along with the type of the database. -/// If the database lifetime did not have a name, then modifies the item function -/// so that it is called `'__db` and returns that. -fn db_lifetime_and_ty(func: &mut syn::Signature) -> syn::Result<(syn::Lifetime, &syn::Type)> { - // If this is a method, then the database should be the second argument. - let db_loc = if matches!(func.inputs[0], syn::FnArg::Receiver(_)) { - 1 - } else { - 0 - }; - match &mut func.inputs[db_loc] { - syn::FnArg::Receiver(r) => Err(syn::Error::new(r.span(), "two self arguments")), - syn::FnArg::Typed(pat_ty) => match &mut *pat_ty.ty { - syn::Type::Reference(ty) => match &ty.lifetime { - Some(lt) => Ok((lt.clone(), &pat_ty.ty)), - None => { - let and_token_span = ty.and_token.span(); - let ident = syn::Ident::new("__db", and_token_span); - func.generics.params.insert( - 0, - syn::LifetimeDef { - attrs: vec![], - lifetime: syn::Lifetime { - apostrophe: and_token_span, - ident: ident.clone(), - }, - colon_token: None, - bounds: Default::default(), - } - .into(), - ); - let db_lifetime = syn::Lifetime { - apostrophe: and_token_span, - ident, - }; - ty.lifetime = Some(db_lifetime.clone()); - Ok((db_lifetime, &pat_ty.ty)) - } - }, - _ => Err(syn::Error::new( - pat_ty.span(), - "expected database to be a `&` type", - )), - }, - } -} - -/// Generates the `accumulated` function, which invokes `accumulated` -/// on the function ingredient to extract the values pushed (transitively) -/// into an accumulator. -fn accumulated_fn( - args: &FnArgs, - item_fn: &syn::ItemFn, - config_ty: &syn::Type, -) -> syn::Result { - let jar_ty = args.jar_ty(); - - let mut accumulated_fn = item_fn.clone(); - accumulated_fn.sig.ident = syn::Ident::new("accumulated", item_fn.sig.ident.span()); - accumulated_fn.sig.generics.params.push(parse_quote! { - __A: salsa::accumulator::Accumulator - }); - accumulated_fn.sig.output = parse_quote! { - -> Vec<<__A as salsa::accumulator::Accumulator>::Data> - }; - - let (db_lifetime, _) = db_lifetime_and_ty(&mut accumulated_fn.sig)?; - let predicate: syn::WherePredicate = parse_quote!(<#jar_ty as salsa::jar::Jar<#db_lifetime>>::DynDb: salsa::storage::HasJar<<__A as salsa::accumulator::Accumulator>::Jar>); - - if let Some(where_clause) = &mut accumulated_fn.sig.generics.where_clause { - where_clause.predicates.push(predicate); - } else { - accumulated_fn.sig.generics.where_clause = parse_quote!(where #predicate); - } - - let (db_var, arg_names) = fn_args(item_fn)?; - accumulated_fn.block = parse_quote! { - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(#db_var); - let __ingredients = <_ as salsa::storage::HasIngredientsFor<#config_ty>>::ingredient(__jar); - let __key = __ingredients.intern_map.intern(__runtime, (#(#arg_names),*)); - __ingredients.function.accumulated::<__A>(#db_var, __key) - } - }; - - Ok(accumulated_fn) -} - -/// Examines the function arguments and returns a tuple of: -/// -/// * the name of the database argument -/// * the name(s) of the key arguments -fn fn_args(item_fn: &syn::ItemFn) -> syn::Result<(proc_macro2::Ident, Vec)> { - // Check that we have no receiver and that all arguments have names - if item_fn.sig.inputs.is_empty() { - return Err(syn::Error::new( - item_fn.sig.span(), - "method needs a database argument", - )); - } - - let mut input_names = vec![]; - for input in &item_fn.sig.inputs { - match input { - syn::FnArg::Receiver(r) => { - return Err(syn::Error::new(r.span(), "no self argument expected")); - } - syn::FnArg::Typed(pat_ty) => match &*pat_ty.pat { - syn::Pat::Ident(ident) => { - input_names.push(ident.ident.clone()); - } - - _ => { - return Err(syn::Error::new( - pat_ty.pat.span(), - "all arguments must be given names", - )); - } - }, - } - } - - // Database is the first argument - let db_var = input_names[0].clone(); - let arg_names = input_names[1..].to_owned(); - - Ok((db_var, arg_names)) -} diff --git a/third-party/vendor/salsa-2022-macros/src/tracked_struct.rs b/third-party/vendor/salsa-2022-macros/src/tracked_struct.rs deleted file mode 100644 index 98f36cf9..00000000 --- a/third-party/vendor/salsa-2022-macros/src/tracked_struct.rs +++ /dev/null @@ -1,324 +0,0 @@ -use proc_macro2::{Literal, TokenStream}; - -use crate::salsa_struct::{SalsaField, SalsaStruct, SalsaStructKind}; - -/// For an tracked struct `Foo` with fields `f1: T1, ..., fN: TN`, we generate... -/// -/// * the "id struct" `struct Foo(salsa::Id)` -/// * the tracked ingredient, which maps the id fields to the `Id` -/// * for each value field, a function ingredient -pub(crate) fn tracked( - args: proc_macro::TokenStream, - struct_item: syn::ItemStruct, -) -> syn::Result { - SalsaStruct::with_struct(SalsaStructKind::Tracked, args, struct_item) - .and_then(|el| TrackedStruct(el).generate_tracked()) -} - -struct TrackedStruct(SalsaStruct); - -impl std::ops::Deref for TrackedStruct { - type Target = SalsaStruct; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl crate::options::AllowedOptions for TrackedStruct { - const RETURN_REF: bool = false; - - const SPECIFY: bool = false; - - const NO_EQ: bool = false; - - const SINGLETON: bool = false; - - const JAR: bool = true; - - const DATA: bool = true; - - const DB: bool = false; - - const RECOVERY_FN: bool = false; - - const LRU: bool = false; - - const CONSTRUCTOR_NAME: bool = true; -} - -impl TrackedStruct { - fn generate_tracked(&self) -> syn::Result { - self.validate_tracked()?; - - let (config_structs, config_impls) = - self.field_config_structs_and_impls(self.value_fields()); - - let id_struct = self.id_struct(); - let inherent_impl = self.tracked_inherent_impl(); - let ingredients_for_impl = self.tracked_struct_ingredients(&config_structs); - let salsa_struct_in_db_impl = self.salsa_struct_in_db_impl(); - let tracked_struct_in_db_impl = self.tracked_struct_in_db_impl(); - let as_id_impl = self.as_id_impl(); - let as_debug_with_db_impl = self.as_debug_with_db_impl(); - Ok(quote! { - #(#config_structs)* - #id_struct - #inherent_impl - #ingredients_for_impl - #salsa_struct_in_db_impl - #tracked_struct_in_db_impl - #as_id_impl - #as_debug_with_db_impl - #(#config_impls)* - }) - } - - fn validate_tracked(&self) -> syn::Result<()> { - Ok(()) - } - - /// Generate an inherent impl with methods on the tracked type. - fn tracked_inherent_impl(&self) -> syn::ItemImpl { - let ident = self.id_ident(); - let jar_ty = self.jar_ty(); - let db_dyn_ty = self.db_dyn_ty(); - let struct_index = self.tracked_struct_index(); - - let id_field_indices: Vec<_> = self.id_field_indices(); - let id_field_names: Vec<_> = self.id_fields().map(SalsaField::name).collect(); - let id_field_get_names: Vec<_> = self.id_fields().map(SalsaField::get_name).collect(); - let id_field_tys: Vec<_> = self.id_fields().map(SalsaField::ty).collect(); - let id_field_vises: Vec<_> = self.id_fields().map(SalsaField::vis).collect(); - let id_field_clones: Vec<_> = self.id_fields().map(SalsaField::is_clone_field).collect(); - let id_field_getters: Vec = id_field_indices.iter().zip(&id_field_get_names).zip(&id_field_tys).zip(&id_field_vises).zip(&id_field_clones).map(|((((field_index, field_get_name), field_ty), field_vis), is_clone_field)| - if !*is_clone_field { - parse_quote! { - #field_vis fn #field_get_name<'db>(self, __db: &'db #db_dyn_ty) -> &'db #field_ty - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - &__ingredients.#struct_index.tracked_struct_data(__runtime, self).#field_index - } - } - } else { - parse_quote! { - #field_vis fn #field_get_name<'db>(self, __db: &'db #db_dyn_ty) -> #field_ty - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - __ingredients.#struct_index.tracked_struct_data(__runtime, self).#field_index.clone() - } - } - } - ) - .collect(); - - let value_field_indices = self.value_field_indices(); - let value_field_names: Vec<_> = self.value_fields().map(SalsaField::name).collect(); - let value_field_vises: Vec<_> = self.value_fields().map(SalsaField::vis).collect(); - let value_field_tys: Vec<_> = self.value_fields().map(SalsaField::ty).collect(); - let value_field_get_names: Vec<_> = self.value_fields().map(SalsaField::get_name).collect(); - let value_field_clones: Vec<_> = self - .value_fields() - .map(SalsaField::is_clone_field) - .collect(); - let value_field_getters: Vec = value_field_indices.iter().zip(&value_field_get_names).zip(&value_field_tys).zip(&value_field_vises).zip(&value_field_clones).map(|((((field_index, field_get_name), field_ty), field_vis), is_clone_field)| - if !*is_clone_field { - parse_quote! { - #field_vis fn #field_get_name<'db>(self, __db: &'db #db_dyn_ty) -> &'db #field_ty - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - __ingredients.#field_index.fetch(__db, self) - } - } - } else { - parse_quote! { - #field_vis fn #field_get_name<'db>(self, __db: &'db #db_dyn_ty) -> #field_ty - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - __ingredients.#field_index.fetch(__db, self).clone() - } - } - } - ) - .collect(); - - let all_field_names = self.all_field_names(); - let all_field_tys = self.all_field_tys(); - let constructor_name = self.constructor_name(); - - parse_quote! { - impl #ident { - pub fn #constructor_name(__db: &#db_dyn_ty, #(#all_field_names: #all_field_tys,)*) -> Self - { - let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db); - let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient(__jar); - let __id = __ingredients.#struct_index.new_struct(__runtime, (#(#id_field_names,)*)); - #( - __ingredients.#value_field_indices.specify_and_record(__db, __id, #value_field_names); - )* - __id - } - - #(#id_field_getters)* - - #(#value_field_getters)* - } - } - } - - /// Generate the `IngredientsFor` impl for this tracked struct. - /// - /// The tracked struct's ingredients include both the main tracked struct ingredient along with a - /// function ingredient for each of the value fields. - fn tracked_struct_ingredients(&self, config_structs: &[syn::ItemStruct]) -> syn::ItemImpl { - use crate::literal; - let ident = self.id_ident(); - let jar_ty = self.jar_ty(); - let id_field_tys: Vec<&syn::Type> = self.id_fields().map(SalsaField::ty).collect(); - let value_field_indices: Vec = self.value_field_indices(); - let tracked_struct_index: Literal = self.tracked_struct_index(); - let config_struct_names = config_structs.iter().map(|s| &s.ident); - let debug_name_struct = literal(self.id_ident()); - let debug_name_fields: Vec<_> = self.all_field_names().into_iter().map(literal).collect(); - - parse_quote! { - impl salsa::storage::IngredientsFor for #ident { - type Jar = #jar_ty; - type Ingredients = ( - #( - salsa::function::FunctionIngredient<#config_struct_names>, - )* - salsa::tracked_struct::TrackedStructIngredient<#ident, (#(#id_field_tys,)*)>, - ); - - fn create_ingredients( - routes: &mut salsa::routes::Routes, - ) -> Self::Ingredients - where - DB: salsa::DbWithJar + salsa::storage::JarFromJars, - { - ( - #( - { - let index = routes.push( - |jars| { - let jar = >::jar_from_jars(jars); - let ingredients = <_ as salsa::storage::HasIngredientsFor>::ingredient(jar); - &ingredients.#value_field_indices - }, - |jars| { - let jar = >::jar_from_jars_mut(jars); - let ingredients = <_ as salsa::storage::HasIngredientsFor>::ingredient_mut(jar); - &mut ingredients.#value_field_indices - }, - ); - salsa::function::FunctionIngredient::new(index, #debug_name_fields) - }, - )* - { - let index = routes.push( - |jars| { - let jar = >::jar_from_jars(jars); - let ingredients = <_ as salsa::storage::HasIngredientsFor>::ingredient(jar); - &ingredients.#tracked_struct_index - }, - |jars| { - let jar = >::jar_from_jars_mut(jars); - let ingredients = <_ as salsa::storage::HasIngredientsFor>::ingredient_mut(jar); - &mut ingredients.#tracked_struct_index - }, - ); - salsa::tracked_struct::TrackedStructIngredient::new(index, #debug_name_struct) - }, - ) - } - } - } - } - - /// Implementation of `SalsaStructInDb`. - fn salsa_struct_in_db_impl(&self) -> syn::ItemImpl { - let ident = self.id_ident(); - let jar_ty = self.jar_ty(); - let tracked_struct_index: Literal = self.tracked_struct_index(); - parse_quote! { - impl salsa::salsa_struct::SalsaStructInDb for #ident - where - DB: ?Sized + salsa::DbWithJar<#jar_ty>, - { - fn register_dependent_fn(db: &DB, index: salsa::routes::IngredientIndex) { - let (jar, _) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(db); - let ingredients = <#jar_ty as salsa::storage::HasIngredientsFor<#ident>>::ingredient(jar); - ingredients.#tracked_struct_index.register_dependent_fn(index) - } - } - } - } - - /// Implementation of `TrackedStructInDb`. - fn tracked_struct_in_db_impl(&self) -> syn::ItemImpl { - let ident = self.id_ident(); - let jar_ty = self.jar_ty(); - let tracked_struct_index = self.tracked_struct_index(); - parse_quote! { - impl salsa::tracked_struct::TrackedStructInDb for #ident - where - DB: ?Sized + salsa::DbWithJar<#jar_ty>, - { - fn database_key_index(self, db: &DB) -> salsa::DatabaseKeyIndex { - let (jar, _) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(db); - let ingredients = <#jar_ty as salsa::storage::HasIngredientsFor<#ident>>::ingredient(jar); - ingredients.#tracked_struct_index.database_key_index(self) - } - } - } - } - - /// List of id fields (fields that are part of the tracked struct's identity across revisions). - /// - /// If this is an enum, empty iterator. - fn id_fields(&self) -> impl Iterator { - self.all_fields().filter(|ef| ef.is_id_field()) - } - - /// List of value fields (fields that are not part of the tracked struct's identity across revisions). - /// - /// If this is an enum, empty iterator. - fn value_fields(&self) -> impl Iterator { - self.all_fields().filter(|ef| !ef.is_id_field()) - } - - /// For this struct, we create a tuple that contains the function ingredients - /// for each "other" field and the tracked-struct ingredient. This is the index of - /// the entity ingredient within that tuple. - fn tracked_struct_index(&self) -> Literal { - Literal::usize_unsuffixed(self.value_fields().count()) - } - - /// For this struct, we create a tuple that contains the function ingredients - /// for each "other" field and the tracked-struct ingredient. These are the indices - /// of the function ingredients within that tuple. - fn value_field_indices(&self) -> Vec { - (0..self.value_fields().count()) - .map(Literal::usize_unsuffixed) - .collect() - } - - /// Indices of each of the id fields - fn id_field_indices(&self) -> Vec { - (0..self.id_fields().count()) - .map(Literal::usize_unsuffixed) - .collect() - } -} - -impl SalsaField { - /// true if this is an id field - fn is_id_field(&self) -> bool { - self.has_id_attr - } -} diff --git a/third-party/vendor/salsa-2022/.cargo-checksum.json b/third-party/vendor/salsa-2022/.cargo-checksum.json deleted file mode 100644 index 85138a2d..00000000 --- a/third-party/vendor/salsa-2022/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"f35473257bf5d695891b12d8cb8fecbec0c9b3554d0526403948c8fd9b7feac2","src/accumulator.rs":"7db47a85280c1db04cc78c03aa6bc5bb0c26b61454d368e6cfdcb94598490e0e","src/cancelled.rs":"e91c330f136988caf78392579e16494f18fb13cdbd03ab60e61d37fd8bda9a6f","src/cycle.rs":"8ab9f86d2f8c23c3f20f13e875ec41cb77f2bb1a2b4c4f93a8dd9c14a5b66a7d","src/database.rs":"4c157b3284ee7d023d149fea0233c165f3a6ea1d6590c7eff52c04929f93588c","src/debug.rs":"cd3618aa5d1351a86255878c1bcea80bbba7b0e3d5b043b11e8cf648d2a52c39","src/durability.rs":"9c1f421f4ba30bdd9c82b72faf4d5ddcabfe2e4b1c5ff8bde5cbdba43dafbc9c","src/event.rs":"38000ec37a21b9af92870a1e958566684c4c1a51154cee8bb6c8819ed29ae4bf","src/function.rs":"c92a17ce17d058cd9d9c127cb6e7d79983e18d9fd5bf7f80ba113681492defbf","src/function/accumulated.rs":"2c3ff43de07c7ead800ccd1328405a2b0f254d4673fb43d6a37a8a59f44ed39a","src/function/backdate.rs":"2900cee87eb0ba5ac067e5357c45e8fde25993792fa8bf347d1d816545386d0c","src/function/delete.rs":"de238c0a867be55a1b26aff51d4bb82e3699361f72b7748cec097f24efdfd611","src/function/diff_outputs.rs":"e8174b5a034bffd4153ea0319cda7ba9fda9a264b96828559744309f16eb6910","src/function/execute.rs":"46292cec28d7fef46f86b5c468beb3f89fee616d97a6b337b0931487502dba6c","src/function/fetch.rs":"f3db15fbd6e88891457ac146611da8c24310682bd940dd160e9e6d7dc65f737c","src/function/inputs.rs":"53f88bbaf39f08afc7da3e41e9a328e0ec875e2ae4aa55da4f8a0160242759e5","src/function/lru.rs":"d79f5d040e8420da62036af31749413de6de9e36a7f45a8e46b3bae3266b3c7c","src/function/maybe_changed_after.rs":"166316b96881e5112266cb69556831162a7432be7fc660763cf6c81bdc5cce3a","src/function/memo.rs":"3dba9207b760682fe0b70d92bfc9600c5367f579b97af24b2ca770adb9f0a24f","src/function/specify.rs":"4cd843cf77952191c4ba970129d889b7f5ea61b32dce9dd9598550a5b06cb052","src/function/store.rs":"a17d7925d93fc5bb67b4c55553332b913379dd76001ab4750464b389a9f66c62","src/function/sync.rs":"8329102bb5129811e141ba9148f3aff1fa481ac1a82cfcc17d15375af10ad26e","src/hash.rs":"c638ac58047cd4a0addc50999fb2e594c92263d6585d743e5df8610aa6c0b942","src/id.rs":"97961be9c6d6e38947195b8bdfb9aa778eadd364f7163a170555ab0fdaea0473","src/ingredient.rs":"fe76b0a78cb1e6e6140afb73f43bb8eba5152684de6d8d0f00bf54302bd8fb13","src/ingredient_list.rs":"8c571b48742d50420caec3f321d6cd20e384525324ad8cad6d0db9c8dd3f67b9","src/input.rs":"1f7cb8fa98c9d079c4277c4c6097636a7a067e650f846ad223d215fada8d2764","src/input_field.rs":"bf06bb30afe1414907f662bb9531a6f9a4fc7f79c57361f10b9c5de3510b7789","src/interned.rs":"66df24f0296cbc2970db73654369ff39e59698fc69c6dbaf0eec2a71e39e1340","src/jar.rs":"f0ffe211f96687a53215656ea5dbab02b0455be59810a308b193644dbcb8c239","src/key.rs":"f5dffd891dc67d7f9bed223e23daba23a17175e3edb3f15adbe577fb35a1672a","src/lib.rs":"6c2904ce25270aa2228534fb8f0d76de6d7d8035cf528d6ea4d390ce0d3b2f31","src/plumbing.rs":"037f43a954ce54fc938f7cfa7cd36d17b2fa25eb31bc1f20d2c68e6ec1ecb83b","src/revision.rs":"69fd5e604e3b8b7159921181fbb1b805e02b659a084f0fb43ceb8ecb7fcd4bec","src/routes.rs":"c05105e7b96d467f8b61098a48143987e71788d6e7f7a8ef28f0819fda5533ab","src/runtime.rs":"f1beadc711af3516a3d5ff9dd73eaeda8ba5e716ee547bbe735ba0f50b2c960e","src/runtime/active_query.rs":"936956b27bb60cd88340975186b36c0c6f0ce9a4d3e77efbc11dec9ce47c4b92","src/runtime/dependency_graph.rs":"4eabe83caf4b2e084639062b5c2247d186c85fc22d1a24b506989b70f575efd1","src/runtime/local_state.rs":"ade47dcfca3e0a48a3f59c0e1d474a7f10ec4b3a7b1556635c81fbf858ed1a60","src/runtime/shared_state.rs":"8aeeae37d2f1fb3ee6efdc745a5bc49c18229e84a4a6bcc05c2b61d461160067","src/salsa_struct.rs":"5951b31e2f457131aeaebef0077a475324c52a19152bbb3984ca1bda5b9e9c81","src/setter.rs":"5d5d82fb95a4e160d3ceb4bfb4c752699b3b3c13c344416dba8d258e38ccc4d7","src/storage.rs":"c7f81757e8cdfba2dc65f741b6679d3c946b59e29e3a5872f129b142716438f1","src/tracked_struct.rs":"edb2e6e529f2feeecddcb944f92e2042980f041f49ed045ecb101f513ffe45cf"},"package":null} \ No newline at end of file diff --git a/third-party/vendor/salsa-2022/Cargo.toml b/third-party/vendor/salsa-2022/Cargo.toml deleted file mode 100644 index 939f6864..00000000 --- a/third-party/vendor/salsa-2022/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "salsa-2022" -version = "0.1.0" - -[dependencies] -arc-swap = "1.4.0" -crossbeam = "0.8.1" -dashmap = "5.3.4" -hashlink = "0.8.0" -indexmap = "2" -log = "0.4.5" -parking_lot = "0.12.1" -rustc-hash = "1.1.0" -smallvec = "1.0.0" - -[dependencies.crossbeam-utils] -version = "0.8" -default-features = false - -[dependencies.salsa-2022-macros] -path = "../salsa-2022-macros" diff --git a/third-party/vendor/salsa-2022/src/accumulator.rs b/third-party/vendor/salsa-2022/src/accumulator.rs deleted file mode 100644 index af22ac84..00000000 --- a/third-party/vendor/salsa-2022/src/accumulator.rs +++ /dev/null @@ -1,172 +0,0 @@ -//! Basic test of accumulator functionality. - -use std::fmt; - -use crate::{ - cycle::CycleRecoveryStrategy, - hash::FxDashMap, - ingredient::{fmt_index, Ingredient, IngredientRequiresReset}, - key::DependencyIndex, - runtime::local_state::QueryOrigin, - storage::HasJar, - DatabaseKeyIndex, Event, EventKind, IngredientIndex, Revision, Runtime, -}; - -pub trait Accumulator { - type Data: Clone; - type Jar; - - fn accumulator_ingredient(db: &Db) -> &AccumulatorIngredient - where - Db: ?Sized + HasJar; -} -pub struct AccumulatorIngredient { - index: IngredientIndex, - map: FxDashMap>, - debug_name: &'static str, -} - -struct AccumulatedValues { - produced_at: Revision, - values: Vec, -} - -impl AccumulatorIngredient { - pub fn new(index: IngredientIndex, debug_name: &'static str) -> Self { - Self { - map: FxDashMap::default(), - index, - debug_name, - } - } - - fn dependency_index(&self) -> DependencyIndex { - DependencyIndex { - ingredient_index: self.index, - key_index: None, - } - } - - pub fn push(&self, runtime: &Runtime, value: Data) { - let current_revision = runtime.current_revision(); - let (active_query, _) = match runtime.active_query() { - Some(pair) => pair, - None => { - panic!("cannot accumulate values outside of an active query") - } - }; - - let mut accumulated_values = self.map.entry(active_query).or_insert(AccumulatedValues { - values: vec![], - produced_at: current_revision, - }); - - // When we call `push' in a query, we will add the accumulator to the output of the query. - // If we find here that this accumulator is not the output of the query, - // we can say that the accumulated values we stored for this query is out of date. - if !runtime.is_output_of_active_query(self.dependency_index()) { - accumulated_values.values.truncate(0); - accumulated_values.produced_at = current_revision; - } - - runtime.add_output(self.dependency_index()); - accumulated_values.values.push(value); - } - - pub(crate) fn produced_by( - &self, - runtime: &Runtime, - query: DatabaseKeyIndex, - output: &mut Vec, - ) { - let current_revision = runtime.current_revision(); - if let Some(v) = self.map.get(&query) { - // FIXME: We don't currently have a good way to identify the value that was read. - // You can't report is as a tracked read of `query`, because the return value of query is not being read here -- - // instead it is the set of values accumuated by `query`. - runtime.report_untracked_read(); - - let AccumulatedValues { - values, - produced_at, - } = v.value(); - - if *produced_at == current_revision { - output.extend(values.iter().cloned()); - } - } - } -} - -impl Ingredient for AccumulatorIngredient -where - DB: crate::Database, - Data: Clone, -{ - fn ingredient_index(&self) -> IngredientIndex { - self.index - } - - fn maybe_changed_after(&self, _db: &DB, _input: DependencyIndex, _revision: Revision) -> bool { - panic!("nothing should ever depend on an accumulator directly") - } - - fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy { - CycleRecoveryStrategy::Panic - } - - fn origin(&self, _key_index: crate::Id) -> Option { - None - } - - fn mark_validated_output( - &self, - db: &DB, - executor: DatabaseKeyIndex, - output_key: Option, - ) { - assert!(output_key.is_none()); - let current_revision = db.runtime().current_revision(); - if let Some(mut v) = self.map.get_mut(&executor) { - // The value is still valid in the new revision. - v.produced_at = current_revision; - } - } - - fn remove_stale_output( - &self, - db: &DB, - executor: DatabaseKeyIndex, - stale_output_key: Option, - ) { - assert!(stale_output_key.is_none()); - if self.map.remove(&executor).is_some() { - db.salsa_event(Event { - runtime_id: db.runtime().id(), - kind: EventKind::DidDiscardAccumulated { - executor_key: executor, - accumulator: self.dependency_index(), - }, - }) - } - } - - fn reset_for_new_revision(&mut self) { - panic!("unexpected reset on accumulator") - } - - fn salsa_struct_deleted(&self, _db: &DB, _id: crate::Id) { - panic!("unexpected call: accumulator is not registered as a dependent fn"); - } - - fn fmt_index(&self, index: Option, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_index(self.debug_name, index, fmt) - } -} - -impl IngredientRequiresReset for AccumulatorIngredient -where - Data: Clone, -{ - const RESET_ON_NEW_REVISION: bool = false; -} diff --git a/third-party/vendor/salsa-2022/src/cancelled.rs b/third-party/vendor/salsa-2022/src/cancelled.rs deleted file mode 100644 index 6c5a6e4c..00000000 --- a/third-party/vendor/salsa-2022/src/cancelled.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::{ - fmt, - panic::{self, UnwindSafe}, -}; - -/// A panic payload indicating that execution of a salsa query was cancelled. -/// -/// This can occur for a few reasons: -/// * -/// * -/// * -#[derive(Debug)] -#[non_exhaustive] -pub enum Cancelled { - /// The query was operating on revision R, but there is a pending write to move to revision R+1. - #[non_exhaustive] - PendingWrite, - - /// The query was blocked on another thread, and that thread panicked. - #[non_exhaustive] - PropagatedPanic, -} - -impl Cancelled { - pub(crate) fn throw(self) -> ! { - // We use resume and not panic here to avoid running the panic - // hook (that is, to avoid collecting and printing backtrace). - std::panic::resume_unwind(Box::new(self)); - } - - /// Runs `f`, and catches any salsa cancellation. - pub fn catch(f: F) -> Result - where - F: FnOnce() -> T + UnwindSafe, - { - match panic::catch_unwind(f) { - Ok(t) => Ok(t), - Err(payload) => match payload.downcast() { - Ok(cancelled) => Err(*cancelled), - Err(payload) => panic::resume_unwind(payload), - }, - } - } -} - -impl std::fmt::Display for Cancelled { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let why = match self { - Cancelled::PendingWrite => "pending write", - Cancelled::PropagatedPanic => "propagated panic", - }; - f.write_str("cancelled because of ")?; - f.write_str(why) - } -} - -impl std::error::Error for Cancelled {} diff --git a/third-party/vendor/salsa-2022/src/cycle.rs b/third-party/vendor/salsa-2022/src/cycle.rs deleted file mode 100644 index d3ba93ce..00000000 --- a/third-party/vendor/salsa-2022/src/cycle.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::debug::DebugWithDb; -use crate::{key::DatabaseKeyIndex, Database}; -use std::{panic::AssertUnwindSafe, sync::Arc}; - -/// Captures the participants of a cycle that occurred when executing a query. -/// -/// This type is meant to be used to help give meaningful error messages to the -/// user or to help salsa developers figure out why their program is resulting -/// in a computation cycle. -/// -/// It is used in a few ways: -/// -/// * During [cycle recovery](https://https://salsa-rs.github.io/salsa/cycles/fallback.html), -/// where it is given to the fallback function. -/// * As the panic value when an unexpected cycle (i.e., a cycle where one or more participants -/// lacks cycle recovery information) occurs. -/// -/// You can read more about cycle handling in -/// the [salsa book](https://https://salsa-rs.github.io/salsa/cycles.html). -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Cycle { - participants: CycleParticipants, -} - -pub(crate) type CycleParticipants = Arc>; - -impl Cycle { - pub(crate) fn new(participants: CycleParticipants) -> Self { - Self { participants } - } - - /// True if two `Cycle` values represent the same cycle. - pub(crate) fn is(&self, cycle: &Cycle) -> bool { - Arc::ptr_eq(&self.participants, &cycle.participants) - } - - pub(crate) fn throw(self) -> ! { - log::debug!("throwing cycle {:?}", self); - std::panic::resume_unwind(Box::new(self)) - } - - pub(crate) fn catch(execute: impl FnOnce() -> T) -> Result { - match std::panic::catch_unwind(AssertUnwindSafe(execute)) { - Ok(v) => Ok(v), - Err(err) => match err.downcast::() { - Ok(cycle) => Err(*cycle), - Err(other) => std::panic::resume_unwind(other), - }, - } - } - - /// Iterate over the [`DatabaseKeyIndex`] for each query participating - /// in the cycle. The start point of this iteration within the cycle - /// is arbitrary but deterministic, but the ordering is otherwise determined - /// by the execution. - pub fn participant_keys(&self) -> impl Iterator + '_ { - self.participants.iter().copied() - } - - /// Returns a vector with the debug information for - /// all the participants in the cycle. - pub fn all_participants(&self, db: &DB) -> Vec { - self.participant_keys() - .map(|d| format!("{:?}", d.debug(db))) - .collect() - } - - /// Returns a vector with the debug information for - /// those participants in the cycle that lacked recovery - /// information. - pub fn unexpected_participants(&self, db: &DB) -> Vec { - self.participant_keys() - .filter(|&d| { - db.cycle_recovery_strategy(d.ingredient_index) == CycleRecoveryStrategy::Panic - }) - .map(|d| format!("{:?}", d.debug(db))) - .collect() - } - - /// Returns a "debug" view onto this strict that can be used to print out information. - pub fn debug<'me, DB: ?Sized + Database>(&'me self, db: &'me DB) -> impl std::fmt::Debug + 'me { - struct UnexpectedCycleDebug<'me> { - c: &'me Cycle, - db: &'me dyn Database, - } - - impl<'me> std::fmt::Debug for UnexpectedCycleDebug<'me> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - fmt.debug_struct("UnexpectedCycle") - .field("all_participants", &self.c.all_participants(self.db)) - .field( - "unexpected_participants", - &self.c.unexpected_participants(self.db), - ) - .finish() - } - } - - UnexpectedCycleDebug { - c: self, - db: db.as_salsa_database(), - } - } -} - -/// Cycle recovery strategy: Is this query capable of recovering from -/// a cycle that results from executing the function? If so, how? -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CycleRecoveryStrategy { - /// Cannot recover from cycles: panic. - /// - /// This is the default. It is also what happens if a cycle - /// occurs and the queries involved have different recovery - /// strategies. - /// - /// In the case of a failure due to a cycle, the panic - /// value will be XXX (FIXME). - Panic, - - /// Recovers from cycles by storing a sentinel value. - /// - /// This value is computed by the `QueryFunction::cycle_fallback` - /// function. - Fallback, -} diff --git a/third-party/vendor/salsa-2022/src/database.rs b/third-party/vendor/salsa-2022/src/database.rs deleted file mode 100644 index 64599196..00000000 --- a/third-party/vendor/salsa-2022/src/database.rs +++ /dev/null @@ -1,138 +0,0 @@ -use crate::{storage::HasJarsDyn, DebugWithDb, Durability, Event}; - -pub trait Database: HasJarsDyn + AsSalsaDatabase { - /// This function is invoked at key points in the salsa - /// runtime. It permits the database to be customized and to - /// inject logging or other custom behavior. - /// - /// By default, the event is logged at level debug using - /// the standard `log` facade. - fn salsa_event(&self, event: Event) { - log::debug!("salsa_event: {:?}", event.debug(self)); - } - - /// A "synthetic write" causes the system to act *as though* some - /// input of durability `durability` has changed. This is mostly - /// useful for profiling scenarios. - /// - /// **WARNING:** Just like an ordinary write, this method triggers - /// cancellation. If you invoke it while a snapshot exists, it - /// will block until that snapshot is dropped -- if that snapshot - /// is owned by the current thread, this could trigger deadlock. - fn synthetic_write(&mut self, durability: Durability) { - self.runtime_mut().report_tracked_write(durability); - } - - /// Reports that the query depends on some state unknown to salsa. - /// - /// Queries which report untracked reads will be re-executed in the next - /// revision. - fn report_untracked_read(&self) { - self.runtime().report_untracked_read(); - } -} - -/// Indicates a database that also supports parallel query -/// evaluation. All of Salsa's base query support is capable of -/// parallel execution, but for it to work, your query key/value types -/// must also be `Send`, as must any additional data in your database. -pub trait ParallelDatabase: Database + Send { - /// Creates a second handle to the database that holds the - /// database fixed at a particular revision. So long as this - /// "frozen" handle exists, any attempt to [`set`] an input will - /// block. - /// - /// [`set`]: struct.QueryTable.html#method.set - /// - /// This is the method you are meant to use most of the time in a - /// parallel setting where modifications may arise asynchronously - /// (e.g., a language server). In this context, it is common to - /// wish to "fork off" a snapshot of the database performing some - /// series of queries in parallel and arranging the results. Using - /// this method for that purpose ensures that those queries will - /// see a consistent view of the database (it is also advisable - /// for those queries to use the [`Runtime::unwind_if_cancelled`] - /// method to check for cancellation). - /// - /// # Panics - /// - /// It is not permitted to create a snapshot from inside of a - /// query. Attepting to do so will panic. - /// - /// # Deadlock warning - /// - /// The intended pattern for snapshots is that, once created, they - /// are sent to another thread and used from there. As such, the - /// `snapshot` acquires a "read lock" on the database -- - /// therefore, so long as the `snapshot` is not dropped, any - /// attempt to `set` a value in the database will block. If the - /// `snapshot` is owned by the same thread that is attempting to - /// `set`, this will cause a problem. - /// - /// # How to implement this - /// - /// Typically, this method will create a second copy of your - /// database type (`MyDatabaseType`, in the example below), - /// cloning over each of the fields from `self` into this new - /// copy. For the field that stores the salsa runtime, you should - /// use [the `Runtime::snapshot` method][rfm] to create a snapshot of the - /// runtime. Finally, package up the result using `Snapshot::new`, - /// which is a simple wrapper type that only gives `&self` access - /// to the database within (thus preventing the use of methods - /// that may mutate the inputs): - /// - /// [rfm]: struct.Runtime.html#method.snapshot - /// - /// ```rust,ignore - /// impl ParallelDatabase for MyDatabaseType { - /// fn snapshot(&self) -> Snapshot { - /// Snapshot::new( - /// MyDatabaseType { - /// runtime: self.storage.snapshot(), - /// other_field: self.other_field.clone(), - /// } - /// ) - /// } - /// } - /// ``` - fn snapshot(&self) -> Snapshot; -} -pub trait AsSalsaDatabase { - fn as_salsa_database(&self) -> &dyn Database; -} - -/// Simple wrapper struct that takes ownership of a database `DB` and -/// only gives `&self` access to it. See [the `snapshot` method][fm] -/// for more details. -/// -/// [fm]: trait.ParallelDatabase.html#method.snapshot -#[derive(Debug)] -pub struct Snapshot -where - DB: ParallelDatabase, -{ - db: DB, -} - -impl Snapshot -where - DB: ParallelDatabase, -{ - /// Creates a `Snapshot` that wraps the given database handle - /// `db`. From this point forward, only shared references to `db` - /// will be possible. - pub fn new(db: DB) -> Self { - Snapshot { db } - } -} - -impl std::ops::Deref for Snapshot -where - DB: ParallelDatabase, -{ - type Target = DB; - - fn deref(&self) -> &DB { - &self.db - } -} diff --git a/third-party/vendor/salsa-2022/src/debug.rs b/third-party/vendor/salsa-2022/src/debug.rs deleted file mode 100644 index 98149c9a..00000000 --- a/third-party/vendor/salsa-2022/src/debug.rs +++ /dev/null @@ -1,247 +0,0 @@ -use std::{ - collections::{HashMap, HashSet}, - fmt, - rc::Rc, - sync::Arc, -}; - -pub trait DebugWithDb { - fn debug<'me, 'db>(&'me self, db: &'me Db) -> DebugWith<'me, Db> - where - Self: Sized + 'me, - { - DebugWith { - value: BoxRef::Ref(self), - db, - include_all_fields: false, - } - } - - fn debug_with<'me, 'db>(&'me self, db: &'me Db, include_all_fields: bool) -> DebugWith<'me, Db> - where - Self: Sized + 'me, - { - DebugWith { - value: BoxRef::Ref(self), - db, - include_all_fields, - } - } - - /// Be careful when using this method inside a tracked function, - /// because the default macro generated implementation will read all fields, - /// maybe introducing undesired dependencies. - fn debug_all<'me, 'db>(&'me self, db: &'me Db) -> DebugWith<'me, Db> - where - Self: Sized + 'me, - { - DebugWith { - value: BoxRef::Ref(self), - db, - include_all_fields: true, - } - } - - fn into_debug<'me, 'db>(self, db: &'me Db) -> DebugWith<'me, Db> - where - Self: Sized + 'me, - { - DebugWith { - value: BoxRef::Box(Box::new(self)), - db, - include_all_fields: false, - } - } - - /// Be careful when using this method inside a tracked function, - /// because the default macro generated implementation will read all fields, - /// maybe introducing undesired dependencies. - fn into_debug_all<'me, 'db>(self, db: &'me Db) -> DebugWith<'me, Db> - where - Self: Sized + 'me, - { - DebugWith { - value: BoxRef::Box(Box::new(self)), - db, - include_all_fields: true, - } - } - - /// if `include_all_fields` is `false` only identity fields should be read, which means: - /// - for [#\[salsa::input\]](salsa_2022_macros::input) no fields - /// - for [#\[salsa::tracked\]](salsa_2022_macros::tracked) only fields with `#[id]` attribute - /// - for [#\[salsa::interned\]](salsa_2022_macros::interned) any field - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result; -} - -pub struct DebugWith<'me, Db: ?Sized> { - value: BoxRef<'me, dyn DebugWithDb + 'me>, - db: &'me Db, - include_all_fields: bool, -} - -enum BoxRef<'me, T: ?Sized> { - Box(Box), - Ref(&'me T), -} - -impl std::ops::Deref for BoxRef<'_, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - match self { - BoxRef::Box(b) => b, - BoxRef::Ref(r) => r, - } - } -} - -impl fmt::Debug for DebugWith<'_, D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - DebugWithDb::fmt(&*self.value, f, self.db, self.include_all_fields) - } -} - -impl DebugWithDb for &T -where - T: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - T::fmt(self, f, db, include_all_fields) - } -} - -impl DebugWithDb for Box -where - T: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - T::fmt(self, f, db, include_all_fields) - } -} - -impl DebugWithDb for Rc -where - T: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - T::fmt(self, f, db, include_all_fields) - } -} - -impl DebugWithDb for Arc -where - T: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - T::fmt(self, f, db, include_all_fields) - } -} - -impl DebugWithDb for Vec -where - T: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - let elements = self.iter().map(|e| e.debug_with(db, include_all_fields)); - f.debug_list().entries(elements).finish() - } -} - -impl DebugWithDb for Option -where - T: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - let me = self.as_ref().map(|v| v.debug_with(db, include_all_fields)); - fmt::Debug::fmt(&me, f) - } -} - -impl DebugWithDb for HashMap -where - K: DebugWithDb, - V: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - let elements = self.iter().map(|(k, v)| { - ( - k.debug_with(db, include_all_fields), - v.debug_with(db, include_all_fields), - ) - }); - f.debug_map().entries(elements).finish() - } -} - -impl DebugWithDb for (A, B) -where - A: DebugWithDb, - B: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - f.debug_tuple("") - .field(&self.0.debug_with(db, include_all_fields)) - .field(&self.1.debug_with(db, include_all_fields)) - .finish() - } -} - -impl DebugWithDb for (A, B, C) -where - A: DebugWithDb, - B: DebugWithDb, - C: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - f.debug_tuple("") - .field(&self.0.debug_with(db, include_all_fields)) - .field(&self.1.debug_with(db, include_all_fields)) - .field(&self.2.debug_with(db, include_all_fields)) - .finish() - } -} - -impl DebugWithDb for HashSet -where - V: DebugWithDb, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>, db: &Db, include_all_fields: bool) -> fmt::Result { - let elements = self.iter().map(|e| e.debug_with(db, include_all_fields)); - f.debug_list().entries(elements).finish() - } -} - -/// This is used by the macro generated code. -/// If the field type implements `DebugWithDb`, uses that, otherwise, uses `Debug`. -/// That's the "has impl" trick (https://github.com/nvzqz/impls#how-it-works) -#[doc(hidden)] -pub mod helper { - use super::{DebugWith, DebugWithDb}; - use std::{fmt, marker::PhantomData}; - - pub trait Fallback { - fn salsa_debug<'a, 'b>( - a: &'a T, - _db: &'b Db, - _include_all_fields: bool, - ) -> &'a dyn fmt::Debug { - a - } - } - - pub struct SalsaDebug(PhantomData, PhantomData); - - impl, Db: ?Sized> SalsaDebug { - #[allow(dead_code)] - pub fn salsa_debug<'a, 'b: 'a>( - a: &'a T, - db: &'b Db, - include_all_fields: bool, - ) -> DebugWith<'a, Db> { - a.debug_with(db, include_all_fields) - } - } - - impl Fallback for Everything {} -} diff --git a/third-party/vendor/salsa-2022/src/durability.rs b/third-party/vendor/salsa-2022/src/durability.rs deleted file mode 100644 index 58a81e37..00000000 --- a/third-party/vendor/salsa-2022/src/durability.rs +++ /dev/null @@ -1,49 +0,0 @@ -/// Describes how likely a value is to change -- how "durable" it is. -/// By default, inputs have `Durability::LOW` and interned values have -/// `Durability::HIGH`. But inputs can be explicitly set with other -/// durabilities. -/// -/// We use durabilities to optimize the work of "revalidating" a query -/// after some input has changed. Ordinarily, in a new revision, -/// queries have to trace all their inputs back to the base inputs to -/// determine if any of those inputs have changed. But if we know that -/// the only changes were to inputs of low durability (the common -/// case), and we know that the query only used inputs of medium -/// durability or higher, then we can skip that enumeration. -/// -/// Typically, one assigns low durabilites to inputs that the user is -/// frequently editing. Medium or high durabilities are used for -/// configuration, the source from library crates, or other things -/// that are unlikely to be edited. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Durability(u8); - -impl Durability { - /// Low durability: things that change frequently. - /// - /// Example: part of the crate being edited - pub const LOW: Durability = Durability(0); - - /// Medium durability: things that change sometimes, but rarely. - /// - /// Example: a Cargo.toml file - pub const MEDIUM: Durability = Durability(1); - - /// High durability: things that are not expected to change under - /// common usage. - /// - /// Example: the standard library or something from crates.io - pub const HIGH: Durability = Durability(2); - - /// The maximum possible durability; equivalent to HIGH but - /// "conceptually" distinct (i.e., if we add more durability - /// levels, this could change). - pub(crate) const MAX: Durability = Self::HIGH; - - /// Number of durability levels. - pub(crate) const LEN: usize = 3; - - pub(crate) fn index(self) -> usize { - self.0 as usize - } -} diff --git a/third-party/vendor/salsa-2022/src/event.rs b/third-party/vendor/salsa-2022/src/event.rs deleted file mode 100644 index ca2b9b68..00000000 --- a/third-party/vendor/salsa-2022/src/event.rs +++ /dev/null @@ -1,221 +0,0 @@ -use crate::{ - debug::DebugWithDb, key::DatabaseKeyIndex, key::DependencyIndex, runtime::RuntimeId, Database, -}; -use std::fmt; - -/// The `Event` struct identifies various notable things that can -/// occur during salsa execution. Instances of this struct are given -/// to `salsa_event`. -pub struct Event { - /// The id of the snapshot that triggered the event. Usually - /// 1-to-1 with a thread, as well. - pub runtime_id: RuntimeId, - - /// What sort of event was it. - pub kind: EventKind, -} - -impl fmt::Debug for Event { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Event") - .field("runtime_id", &self.runtime_id) - .field("kind", &self.kind) - .finish() - } -} - -impl DebugWithDb for Event -where - Db: ?Sized + Database, -{ - fn fmt( - &self, - f: &mut std::fmt::Formatter<'_>, - db: &Db, - include_all_fields: bool, - ) -> std::fmt::Result { - f.debug_struct("Event") - .field("runtime_id", &self.runtime_id) - .field("kind", &self.kind.debug_with(db, include_all_fields)) - .finish() - } -} - -/// An enum identifying the various kinds of events that can occur. -pub enum EventKind { - /// Occurs when we found that all inputs to a memoized value are - /// up-to-date and hence the value can be re-used without - /// executing the closure. - /// - /// Executes before the "re-used" value is returned. - DidValidateMemoizedValue { - /// The database-key for the affected value. Implements `Debug`. - database_key: DatabaseKeyIndex, - }, - - /// Indicates that another thread (with id `other_runtime_id`) is processing the - /// given query (`database_key`), so we will block until they - /// finish. - /// - /// Executes after we have registered with the other thread but - /// before they have answered us. - /// - /// (NB: you can find the `id` of the current thread via the - /// `runtime`) - WillBlockOn { - /// The id of the runtime we will block on. - other_runtime_id: RuntimeId, - - /// The database-key for the affected value. Implements `Debug`. - database_key: DatabaseKeyIndex, - }, - - /// Indicates that the function for this query will be executed. - /// This is either because it has never executed before or because - /// its inputs may be out of date. - WillExecute { - /// The database-key for the affected value. Implements `Debug`. - database_key: DatabaseKeyIndex, - }, - - /// Indicates that `unwind_if_cancelled` was called and salsa will check if - /// the current revision has been cancelled. - WillCheckCancellation, - - /// Discovered that a query used to output a given output but no longer does. - WillDiscardStaleOutput { - /// Key for the query that is executing and which no longer outputs the given value. - execute_key: DatabaseKeyIndex, - - /// Key for the query that is no longer output - output_key: DependencyIndex, - }, - - /// Tracked structs or memoized data were discarded (freed). - DidDiscard { - /// Value being discarded. - key: DatabaseKeyIndex, - }, - - /// Discarded accumulated data from a given fn - DidDiscardAccumulated { - /// The key of the fn that accumulated results - executor_key: DatabaseKeyIndex, - - /// Accumulator that was accumulated into - accumulator: DependencyIndex, - }, -} - -impl fmt::Debug for EventKind { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - EventKind::DidValidateMemoizedValue { database_key } => fmt - .debug_struct("DidValidateMemoizedValue") - .field("database_key", database_key) - .finish(), - EventKind::WillBlockOn { - other_runtime_id, - database_key, - } => fmt - .debug_struct("WillBlockOn") - .field("other_runtime_id", other_runtime_id) - .field("database_key", database_key) - .finish(), - EventKind::WillExecute { database_key } => fmt - .debug_struct("WillExecute") - .field("database_key", database_key) - .finish(), - EventKind::WillCheckCancellation => fmt.debug_struct("WillCheckCancellation").finish(), - EventKind::WillDiscardStaleOutput { - execute_key, - output_key, - } => fmt - .debug_struct("WillDiscardStaleOutput") - .field("execute_key", &execute_key) - .field("output_key", &output_key) - .finish(), - EventKind::DidDiscard { key } => { - fmt.debug_struct("DidDiscard").field("key", &key).finish() - } - EventKind::DidDiscardAccumulated { - executor_key, - accumulator, - } => fmt - .debug_struct("DidDiscardAccumulated") - .field("executor_key", executor_key) - .field("accumulator", accumulator) - .finish(), - } - } -} - -impl DebugWithDb for EventKind -where - Db: ?Sized + Database, -{ - fn fmt( - &self, - fmt: &mut std::fmt::Formatter<'_>, - db: &Db, - include_all_fields: bool, - ) -> std::fmt::Result { - match self { - EventKind::DidValidateMemoizedValue { database_key } => fmt - .debug_struct("DidValidateMemoizedValue") - .field( - "database_key", - &database_key.debug_with(db, include_all_fields), - ) - .finish(), - EventKind::WillBlockOn { - other_runtime_id, - database_key, - } => fmt - .debug_struct("WillBlockOn") - .field("other_runtime_id", other_runtime_id) - .field( - "database_key", - &database_key.debug_with(db, include_all_fields), - ) - .finish(), - EventKind::WillExecute { database_key } => fmt - .debug_struct("WillExecute") - .field( - "database_key", - &database_key.debug_with(db, include_all_fields), - ) - .finish(), - EventKind::WillCheckCancellation => fmt.debug_struct("WillCheckCancellation").finish(), - EventKind::WillDiscardStaleOutput { - execute_key, - output_key, - } => fmt - .debug_struct("WillDiscardStaleOutput") - .field( - "execute_key", - &execute_key.debug_with(db, include_all_fields), - ) - .field("output_key", &output_key.debug_with(db, include_all_fields)) - .finish(), - EventKind::DidDiscard { key } => fmt - .debug_struct("DidDiscard") - .field("key", &key.debug_with(db, include_all_fields)) - .finish(), - EventKind::DidDiscardAccumulated { - executor_key, - accumulator, - } => fmt - .debug_struct("DidDiscardAccumulated") - .field( - "executor_key", - &executor_key.debug_with(db, include_all_fields), - ) - .field( - "accumulator", - &accumulator.debug_with(db, include_all_fields), - ) - .finish(), - } - } -} diff --git a/third-party/vendor/salsa-2022/src/function.rs b/third-party/vendor/salsa-2022/src/function.rs deleted file mode 100644 index 41b25c0a..00000000 --- a/third-party/vendor/salsa-2022/src/function.rs +++ /dev/null @@ -1,290 +0,0 @@ -use std::{fmt, sync::Arc}; - -use arc_swap::ArcSwap; -use crossbeam::{atomic::AtomicCell, queue::SegQueue}; - -use crate::{ - cycle::CycleRecoveryStrategy, - ingredient::{fmt_index, IngredientRequiresReset}, - jar::Jar, - key::{DatabaseKeyIndex, DependencyIndex}, - runtime::local_state::QueryOrigin, - salsa_struct::SalsaStructInDb, - Cycle, DbWithJar, Event, EventKind, Id, Revision, -}; - -use super::{ingredient::Ingredient, routes::IngredientIndex, AsId}; - -mod accumulated; -mod backdate; -mod delete; -mod diff_outputs; -mod execute; -mod fetch; -mod inputs; -mod lru; -mod maybe_changed_after; -mod memo; -mod specify; -mod store; -mod sync; - -/// Function ingredients are the "workhorse" of salsa. -/// They are used for tracked functions, for the "value" fields of tracked structs, and for the fields of input structs. -/// The function ingredient is fairly complex and so its code is spread across multiple modules, typically one per method. -/// The main entry points are: -/// -/// * the `fetch` method, which is invoked when the function is called by the user's code; -/// it will return a memoized value if one exists, or execute the function otherwise. -/// * the `specify` method, which can only be used when the key is an entity created by the active query. -/// It sets the value of the function imperatively, so that when later fetches occur, they'll return this value. -/// * the `store` method, which can only be invoked with an `&mut` reference, and is to set input fields. -pub struct FunctionIngredient { - /// The ingredient index we were assigned in the database. - /// Used to construct `DatabaseKeyIndex` values. - index: IngredientIndex, - - /// Tracks the keys for which we have memoized values. - memo_map: memo::MemoMap, - - /// Tracks the keys that are currently being processed; used to coordinate between - /// worker threads. - sync_map: sync::SyncMap, - - /// Used to find memos to throw out when we have too many memoized values. - lru: lru::Lru, - - /// When `fetch` and friends executes, they return a reference to the - /// value stored in the memo that is extended to live as long as the `&self` - /// reference we start with. This means that whenever we remove something - /// from `memo_map` with an `&self` reference, there *could* be references to its - /// internals still in use. Therefore we push the memo into this queue and - /// only *actually* free up memory when a new revision starts (which means - /// we have an `&mut` reference to self). - /// - /// You might think that we could do this only if the memo was verified in the - /// current revision: you would be right, but we are being defensive, because - /// we don't know that we can trust the database to give us the same runtime - /// everytime and so forth. - deleted_entries: SegQueue>>, - - /// Set to true once we invoke `register_dependent_fn` for `C::SalsaStruct`. - /// Prevents us from registering more than once. - registered: AtomicCell, - - debug_name: &'static str, -} - -pub trait Configuration { - type Jar: for<'db> Jar<'db>; - - /// The "salsa struct type" that this function is associated with. - /// This can be just `salsa::Id` for functions that intern their arguments - /// and are not clearly associated with any one salsa struct. - type SalsaStruct: for<'db> SalsaStructInDb>; - - /// What key is used to index the memo. Typically a salsa struct id, - /// but if this memoized function has multiple arguments it will be a `salsa::Id` - /// that results from interning those arguments. - type Key: AsId; - - /// The value computed by the function. - type Value: fmt::Debug; - - /// Determines whether this function can recover from being a participant in a cycle - /// (and, if so, how). - const CYCLE_STRATEGY: CycleRecoveryStrategy; - - /// Invokes after a new result `new_value`` has been computed for which an older memoized - /// value existed `old_value`. Returns true if the new value is equal to the older one - /// and hence should be "backdated" (i.e., marked as having last changed in an older revision, - /// even though it was recomputed). - /// - /// This invokes user's code in form of the `Eq` impl. - fn should_backdate_value(old_value: &Self::Value, new_value: &Self::Value) -> bool; - - /// Invoked when we need to compute the value for the given key, either because we've never - /// computed it before or because the old one relied on inputs that have changed. - /// - /// This invokes the function the user wrote. - fn execute(db: &DynDb, key: Self::Key) -> Self::Value; - - /// If the cycle strategy is `Recover`, then invoked when `key` is a participant - /// in a cycle to find out what value it should have. - /// - /// This invokes the recovery function given by the user. - fn recover_from_cycle(db: &DynDb, cycle: &Cycle, key: Self::Key) -> Self::Value; - - /// Given a salsa Id, returns the key. Convenience function to avoid - /// having to type `::from_id`. - fn key_from_id(id: Id) -> Self::Key { - AsId::from_id(id) - } -} - -/// True if `old_value == new_value`. Invoked by the generated -/// code for `should_backdate_value` so as to give a better -/// error message. -pub fn should_backdate_value(old_value: &V, new_value: &V) -> bool { - old_value == new_value -} - -pub type DynDb<'bound, C> = <::Jar as Jar<'bound>>::DynDb; - -/// This type is used to make configuration types for the functions in entities; -/// e.g. you can do `Config` and `Config`. -pub struct Config(std::marker::PhantomData<[(); C]>); - -impl FunctionIngredient -where - C: Configuration, -{ - pub fn new(index: IngredientIndex, debug_name: &'static str) -> Self { - Self { - index, - memo_map: memo::MemoMap::default(), - lru: Default::default(), - sync_map: Default::default(), - deleted_entries: Default::default(), - registered: Default::default(), - debug_name, - } - } - - fn database_key_index(&self, k: C::Key) -> DatabaseKeyIndex { - DatabaseKeyIndex { - ingredient_index: self.index, - key_index: k.as_id(), - } - } - - pub fn set_capacity(&self, capacity: usize) { - self.lru.set_capacity(capacity); - } - - /// Returns a reference to the memo value that lives as long as self. - /// This is UNSAFE: the caller is responsible for ensuring that the - /// memo will not be released so long as the `&self` is valid. - /// This is done by (a) ensuring the memo is present in the memo-map - /// when this function is called and (b) ensuring that any entries - /// removed from the memo-map are added to `deleted_entries`, which is - /// only cleared with `&mut self`. - unsafe fn extend_memo_lifetime<'this, 'memo>( - &'this self, - memo: &'memo memo::Memo, - ) -> Option<&'this C::Value> { - let memo_value: Option<&'memo C::Value> = memo.value.as_ref(); - std::mem::transmute(memo_value) - } - - fn insert_memo( - &self, - db: &DynDb<'_, C>, - key: C::Key, - memo: memo::Memo, - ) -> Option<&C::Value> { - self.register(db); - let memo = Arc::new(memo); - let value = unsafe { - // Unsafety conditions: memo must be in the map (it's not yet, but it will be by the time this - // value is returned) and anything removed from map is added to deleted entries (ensured elsewhere). - self.extend_memo_lifetime(&memo) - }; - if let Some(old_value) = self.memo_map.insert(key, memo) { - // In case there is a reference to the old memo out there, we have to store it - // in the deleted entries. This will get cleared when a new revision starts. - self.deleted_entries.push(old_value); - } - value - } - - /// Register this function as a dependent fn of the given salsa struct. - /// When instances of that salsa struct are deleted, we'll get a callback - /// so we can remove any data keyed by them. - fn register(&self, db: &DynDb<'_, C>) { - if !self.registered.fetch_or(true) { - >::register_dependent_fn(db, self.index) - } - } -} - -impl Ingredient for FunctionIngredient -where - DB: ?Sized + DbWithJar, - C: Configuration, -{ - fn ingredient_index(&self) -> IngredientIndex { - self.index - } - - fn maybe_changed_after(&self, db: &DB, input: DependencyIndex, revision: Revision) -> bool { - let key = C::key_from_id(input.key_index.unwrap()); - let db = db.as_jar_db(); - self.maybe_changed_after(db, key, revision) - } - - fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy { - C::CYCLE_STRATEGY - } - - fn origin(&self, key_index: Id) -> Option { - let key = C::key_from_id(key_index); - self.origin(key) - } - - fn mark_validated_output( - &self, - db: &DB, - executor: DatabaseKeyIndex, - output_key: Option, - ) { - let output_key = C::key_from_id(output_key.unwrap()); - self.validate_specified_value(db.as_jar_db(), executor, output_key); - } - - fn remove_stale_output( - &self, - _db: &DB, - _executor: DatabaseKeyIndex, - _stale_output_key: Option, - ) { - // This function is invoked when a query Q specifies the value for `stale_output_key` in rev 1, - // but not in rev 2. We don't do anything in this case, we just leave the (now stale) memo. - // Since its `verified_at` field has not changed, it will be considered dirty if it is invoked. - } - - fn reset_for_new_revision(&mut self) { - std::mem::take(&mut self.deleted_entries); - } - - fn salsa_struct_deleted(&self, db: &DB, id: crate::Id) { - // Remove any data keyed by `id`, since `id` no longer - // exists in this revision. - - let id: C::Key = C::key_from_id(id); - if let Some(origin) = self.delete_memo(id) { - let key = self.database_key_index(id); - db.salsa_event(Event { - runtime_id: db.runtime().id(), - kind: EventKind::DidDiscard { key }, - }); - - // Anything that was output by this memoized execution - // is now itself stale. - for stale_output in origin.outputs() { - db.remove_stale_output(key, stale_output) - } - } - } - - fn fmt_index(&self, index: Option, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_index(self.debug_name, index, fmt) - } -} - -impl IngredientRequiresReset for FunctionIngredient -where - C: Configuration, -{ - const RESET_ON_NEW_REVISION: bool = true; -} diff --git a/third-party/vendor/salsa-2022/src/function/accumulated.rs b/third-party/vendor/salsa-2022/src/function/accumulated.rs deleted file mode 100644 index 9ee8b9e3..00000000 --- a/third-party/vendor/salsa-2022/src/function/accumulated.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::{ - hash::FxHashSet, - runtime::local_state::QueryOrigin, - storage::{HasJar, HasJarsDyn}, - DatabaseKeyIndex, -}; - -use super::{Configuration, DynDb, FunctionIngredient}; -use crate::accumulator::Accumulator; - -impl FunctionIngredient -where - C: Configuration, -{ - /// Returns all the values accumulated into `accumulator` by this query and its - /// transitive inputs. - pub fn accumulated<'db, A>(&self, db: &DynDb<'db, C>, key: C::Key) -> Vec - where - DynDb<'db, C>: HasJar, - A: Accumulator, - { - // To start, ensure that the value is up to date: - self.fetch(db, key); - - // Now walk over all the things that the value depended on - // and find the values they accumulated into the given - // accumulator: - let runtime = db.runtime(); - let mut result = vec![]; - let accumulator_ingredient = A::accumulator_ingredient(db); - let mut stack = Stack::new(self.database_key_index(key)); - while let Some(input) = stack.pop() { - accumulator_ingredient.produced_by(runtime, input, &mut result); - stack.extend(db.origin(input)); - } - result - } -} - -/// The stack is used to execute a DFS across all the queries -/// that were transitively executed by some given start query. -/// When we visit a query Q0, we look at its dependencies Q1...Qn, -/// and if they have not already been visited, we push them on the stack. -struct Stack { - /// Stack of queries left to visit. - v: Vec, - - /// Set of all queries we've seen. - s: FxHashSet, -} - -impl Stack { - fn new(start: DatabaseKeyIndex) -> Self { - Self { - v: vec![start], - s: FxHashSet::default(), - } - } - - fn pop(&mut self) -> Option { - self.v.pop() - } - - /// Extend the stack of queries with the dependencies from `origin`. - fn extend(&mut self, origin: Option) { - match origin { - None | Some(QueryOrigin::Assigned(_)) | Some(QueryOrigin::BaseInput) => {} - Some(QueryOrigin::Derived(edges)) | Some(QueryOrigin::DerivedUntracked(edges)) => { - for dependency_index in edges.inputs() { - if let Ok(i) = DatabaseKeyIndex::try_from(dependency_index) { - if self.s.insert(i) { - self.v.push(i) - } - } - } - } - } - } -} diff --git a/third-party/vendor/salsa-2022/src/function/backdate.rs b/third-party/vendor/salsa-2022/src/function/backdate.rs deleted file mode 100644 index 9695eebf..00000000 --- a/third-party/vendor/salsa-2022/src/function/backdate.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::runtime::local_state::QueryRevisions; - -use super::{memo::Memo, Configuration, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - /// If the value/durability of this memo is equal to what is found in `revisions`/`value`, - /// then updates `revisions.changed_at` to match `self.revisions.changed_at`. This is invoked - /// on an old memo when a new memo has been produced to check whether there have been changed. - pub(super) fn backdate_if_appropriate( - &self, - old_memo: &Memo, - revisions: &mut QueryRevisions, - value: &C::Value, - ) { - if let Some(old_value) = &old_memo.value { - // Careful: if the value became less durable than it - // used to be, that is a "breaking change" that our - // consumers must be aware of. Becoming *more* durable - // is not. See the test `constant_to_non_constant`. - if revisions.durability >= old_memo.revisions.durability - && C::should_backdate_value(old_value, value) - { - log::debug!( - "value is equal, back-dating to {:?}", - old_memo.revisions.changed_at, - ); - - assert!(old_memo.revisions.changed_at <= revisions.changed_at); - revisions.changed_at = old_memo.revisions.changed_at; - } - } - } -} diff --git a/third-party/vendor/salsa-2022/src/function/delete.rs b/third-party/vendor/salsa-2022/src/function/delete.rs deleted file mode 100644 index 54796bc5..00000000 --- a/third-party/vendor/salsa-2022/src/function/delete.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::runtime::local_state::QueryOrigin; - -use super::{Configuration, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - /// Removes the memoized value for `key` from the memo-map. - /// Pushes the memo onto `deleted_entries` to ensure that any references into that memo which were handed out remain valid. - pub(super) fn delete_memo(&self, key: C::Key) -> Option { - if let Some(memo) = self.memo_map.remove(key) { - let origin = memo.load().revisions.origin.clone(); - self.deleted_entries.push(memo); - Some(origin) - } else { - None - } - } -} diff --git a/third-party/vendor/salsa-2022/src/function/diff_outputs.rs b/third-party/vendor/salsa-2022/src/function/diff_outputs.rs deleted file mode 100644 index c8f8fc63..00000000 --- a/third-party/vendor/salsa-2022/src/function/diff_outputs.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::{ - hash::FxHashSet, key::DependencyIndex, runtime::local_state::QueryRevisions, - storage::HasJarsDyn, Database, DatabaseKeyIndex, Event, EventKind, -}; - -use super::{memo::Memo, Configuration, DynDb, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - /// Compute the old and new outputs and invoke the `clear_stale_output` callback - /// for each output that was generated before but is not generated now. - pub(super) fn diff_outputs( - &self, - db: &DynDb<'_, C>, - key: DatabaseKeyIndex, - old_memo: &Memo, - revisions: &QueryRevisions, - ) { - // Iterate over the outputs of the `old_memo` and put them into a hashset - let mut old_outputs = FxHashSet::default(); - old_memo.revisions.origin.outputs().for_each(|i| { - old_outputs.insert(i); - }); - - // Iterate over the outputs of the current query - // and remove elements from `old_outputs` when we find them - for new_output in revisions.origin.outputs() { - if old_outputs.contains(&new_output) { - old_outputs.remove(&new_output); - } - } - - for old_output in old_outputs { - Self::report_stale_output(db, key, old_output); - } - } - - fn report_stale_output(db: &DynDb<'_, C>, key: DatabaseKeyIndex, output: DependencyIndex) { - let runtime_id = db.runtime().id(); - db.salsa_event(Event { - runtime_id, - kind: EventKind::WillDiscardStaleOutput { - execute_key: key, - output_key: output, - }, - }); - - db.remove_stale_output(key, output); - } -} diff --git a/third-party/vendor/salsa-2022/src/function/execute.rs b/third-party/vendor/salsa-2022/src/function/execute.rs deleted file mode 100644 index c05ad328..00000000 --- a/third-party/vendor/salsa-2022/src/function/execute.rs +++ /dev/null @@ -1,112 +0,0 @@ -use std::sync::Arc; - -use crate::{ - debug::DebugWithDb, - runtime::{local_state::ActiveQueryGuard, StampedValue}, - storage::HasJarsDyn, - Cycle, Database, Event, EventKind, -}; - -use super::{memo::Memo, Configuration, DynDb, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - /// Executes the query function for the given `active_query`. Creates and stores - /// a new memo with the result, backdated if possible. Once this completes, - /// the query will have been popped off the active query stack. - /// - /// # Parameters - /// - /// * `db`, the database. - /// * `active_query`, the active stack frame for the query to execute. - /// * `opt_old_memo`, the older memo, if any existed. Used for backdated. - pub(super) fn execute( - &self, - db: &DynDb, - active_query: ActiveQueryGuard<'_>, - opt_old_memo: Option>>, - ) -> StampedValue<&C::Value> { - let runtime = db.runtime(); - let revision_now = runtime.current_revision(); - let database_key_index = active_query.database_key_index; - - log::info!("{:?}: executing query", database_key_index); - - db.salsa_event(Event { - runtime_id: runtime.id(), - kind: EventKind::WillExecute { - database_key: database_key_index, - }, - }); - - // Query was not previously executed, or value is potentially - // stale, or value is absent. Let's execute! - let database_key_index = active_query.database_key_index; - let key = C::key_from_id(database_key_index.key_index); - let value = match Cycle::catch(|| C::execute(db, key)) { - Ok(v) => v, - Err(cycle) => { - log::debug!( - "{:?}: caught cycle {:?}, have strategy {:?}", - database_key_index.debug(db), - cycle, - C::CYCLE_STRATEGY - ); - match C::CYCLE_STRATEGY { - crate::cycle::CycleRecoveryStrategy::Panic => cycle.throw(), - crate::cycle::CycleRecoveryStrategy::Fallback => { - if let Some(c) = active_query.take_cycle() { - assert!(c.is(&cycle)); - C::recover_from_cycle(db, &cycle, key) - } else { - // we are not a participant in this cycle - debug_assert!(!cycle - .participant_keys() - .any(|k| k == database_key_index)); - cycle.throw() - } - } - } - } - }; - let mut revisions = active_query.pop(runtime); - - // We assume that query is side-effect free -- that is, does - // not mutate the "inputs" to the query system. Sanity check - // that assumption here, at least to the best of our ability. - assert_eq!( - runtime.current_revision(), - revision_now, - "revision altered during query execution", - ); - - // If the new value is equal to the old one, then it didn't - // really change, even if some of its inputs have. So we can - // "backdate" its `changed_at` revision to be the same as the - // old value. - if let Some(old_memo) = &opt_old_memo { - self.backdate_if_appropriate(old_memo, &mut revisions, &value); - self.diff_outputs(db, database_key_index, old_memo, &revisions); - } - - let value = self - .insert_memo( - db, - key, - Memo::new(Some(value), revision_now, revisions.clone()), - ) - .unwrap(); - - let stamped_value = revisions.stamped_value(value); - - log::debug!( - "{:?}: read_upgrade: result.revisions = {:#?}", - database_key_index.debug(db), - revisions - ); - - stamped_value - } -} diff --git a/third-party/vendor/salsa-2022/src/function/fetch.rs b/third-party/vendor/salsa-2022/src/function/fetch.rs deleted file mode 100644 index ffba9981..00000000 --- a/third-party/vendor/salsa-2022/src/function/fetch.rs +++ /dev/null @@ -1,93 +0,0 @@ -use arc_swap::Guard; - -use crate::{database::AsSalsaDatabase, runtime::StampedValue, storage::HasJarsDyn, AsId}; - -use super::{Configuration, DynDb, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - pub fn fetch(&self, db: &DynDb, key: C::Key) -> &C::Value { - let runtime = db.runtime(); - - runtime.unwind_if_revision_cancelled(db); - - let StampedValue { - value, - durability, - changed_at, - } = self.compute_value(db, key); - - if let Some(evicted) = self.lru.record_use(key.as_id()) { - self.evict(AsId::from_id(evicted)); - } - - db.runtime().report_tracked_read( - self.database_key_index(key).into(), - durability, - changed_at, - ); - - value - } - - #[inline] - fn compute_value(&self, db: &DynDb, key: C::Key) -> StampedValue<&C::Value> { - loop { - if let Some(value) = self.fetch_hot(db, key).or_else(|| self.fetch_cold(db, key)) { - return value; - } - } - } - - #[inline] - fn fetch_hot(&self, db: &DynDb, key: C::Key) -> Option> { - let memo_guard = self.memo_map.get(key); - if let Some(memo) = &memo_guard { - if memo.value.is_some() { - let runtime = db.runtime(); - if self.shallow_verify_memo(db, runtime, self.database_key_index(key), memo) { - let value = unsafe { - // Unsafety invariant: memo is present in memo_map - self.extend_memo_lifetime(memo).unwrap() - }; - return Some(memo.revisions.stamped_value(value)); - } - } - } - None - } - - fn fetch_cold(&self, db: &DynDb, key: C::Key) -> Option> { - let runtime = db.runtime(); - let database_key_index = self.database_key_index(key); - - // Try to claim this query: if someone else has claimed it already, go back and start again. - let _claim_guard = self - .sync_map - .claim(db.as_salsa_database(), database_key_index)?; - - // Push the query on the stack. - let active_query = runtime.push_query(database_key_index); - - // Now that we've claimed the item, check again to see if there's a "hot" value. - // This time we can do a *deep* verify. Because this can recurse, don't hold the arcswap guard. - let opt_old_memo = self.memo_map.get(key).map(Guard::into_inner); - if let Some(old_memo) = &opt_old_memo { - if old_memo.value.is_some() && self.deep_verify_memo(db, old_memo, &active_query) { - let value = unsafe { - // Unsafety invariant: memo is present in memo_map. - self.extend_memo_lifetime(old_memo).unwrap() - }; - return Some(old_memo.revisions.stamped_value(value)); - } - } - - Some(self.execute(db, active_query, opt_old_memo)) - } - - fn evict(&self, key: C::Key) { - self.memo_map.evict(key); - } -} diff --git a/third-party/vendor/salsa-2022/src/function/inputs.rs b/third-party/vendor/salsa-2022/src/function/inputs.rs deleted file mode 100644 index 8f2b2241..00000000 --- a/third-party/vendor/salsa-2022/src/function/inputs.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::runtime::local_state::QueryOrigin; - -use super::{Configuration, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - pub(super) fn origin(&self, key: C::Key) -> Option { - self.memo_map.get(key).map(|m| m.revisions.origin.clone()) - } -} diff --git a/third-party/vendor/salsa-2022/src/function/lru.rs b/third-party/vendor/salsa-2022/src/function/lru.rs deleted file mode 100644 index fdc80073..00000000 --- a/third-party/vendor/salsa-2022/src/function/lru.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::{hash::FxLinkedHashSet, Id}; - -use crossbeam_utils::atomic::AtomicCell; -use parking_lot::Mutex; - -#[derive(Default)] -pub(super) struct Lru { - capacity: AtomicCell, - set: Mutex>, -} - -impl Lru { - pub(super) fn record_use(&self, index: Id) -> Option { - let capacity = self.capacity.load(); - - if capacity == 0 { - // LRU is disabled - return None; - } - - let mut set = self.set.lock(); - set.insert(index); - if set.len() > capacity { - return set.pop_front(); - } - - None - } - - pub(super) fn set_capacity(&self, capacity: usize) { - self.capacity.store(capacity); - - if capacity == 0 { - let mut set = self.set.lock(); - *set = FxLinkedHashSet::default(); - } - } -} diff --git a/third-party/vendor/salsa-2022/src/function/maybe_changed_after.rs b/third-party/vendor/salsa-2022/src/function/maybe_changed_after.rs deleted file mode 100644 index 5ab74d60..00000000 --- a/third-party/vendor/salsa-2022/src/function/maybe_changed_after.rs +++ /dev/null @@ -1,223 +0,0 @@ -use arc_swap::Guard; - -use crate::{ - database::AsSalsaDatabase, - debug::DebugWithDb, - key::DatabaseKeyIndex, - runtime::{ - local_state::{ActiveQueryGuard, EdgeKind, QueryOrigin}, - StampedValue, - }, - storage::HasJarsDyn, - Revision, Runtime, -}; - -use super::{memo::Memo, Configuration, DynDb, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - pub(super) fn maybe_changed_after( - &self, - db: &DynDb, - key: C::Key, - revision: Revision, - ) -> bool { - let runtime = db.runtime(); - runtime.unwind_if_revision_cancelled(db); - - loop { - let database_key_index = self.database_key_index(key); - - log::debug!( - "{:?}: maybe_changed_after(revision = {:?})", - database_key_index.debug(db), - revision, - ); - - // Check if we have a verified version: this is the hot path. - let memo_guard = self.memo_map.get(key); - if let Some(memo) = &memo_guard { - if self.shallow_verify_memo(db, runtime, database_key_index, memo) { - return memo.revisions.changed_at > revision; - } - drop(memo_guard); // release the arc-swap guard before cold path - if let Some(mcs) = self.maybe_changed_after_cold(db, key, revision) { - return mcs; - } else { - // We failed to claim, have to retry. - } - } else { - // No memo? Assume has changed. - return true; - } - } - } - - fn maybe_changed_after_cold( - &self, - db: &DynDb, - key_index: C::Key, - revision: Revision, - ) -> Option { - let runtime = db.runtime(); - let database_key_index = self.database_key_index(key_index); - - let _claim_guard = self - .sync_map - .claim(db.as_salsa_database(), database_key_index)?; - let active_query = runtime.push_query(database_key_index); - - // Load the current memo, if any. Use a real arc, not an arc-swap guard, - // since we may recurse. - let old_memo = match self.memo_map.get(key_index) { - Some(m) => Guard::into_inner(m), - None => return Some(true), - }; - - log::debug!( - "{:?}: maybe_changed_after_cold, successful claim, revision = {:?}, old_memo = {:#?}", - database_key_index.debug(db), - revision, - old_memo - ); - - // Check if the inputs are still valid and we can just compare `changed_at`. - if self.deep_verify_memo(db, &old_memo, &active_query) { - return Some(old_memo.revisions.changed_at > revision); - } - - // If inputs have changed, but we have an old value, we can re-execute. - // It is possible the result will be equal to the old value and hence - // backdated. In that case, although we will have computed a new memo, - // the value has not logically changed. - if old_memo.value.is_some() { - let StampedValue { changed_at, .. } = self.execute(db, active_query, Some(old_memo)); - return Some(changed_at > revision); - } - - // Otherwise, nothing for it: have to consider the value to have changed. - Some(true) - } - - /// True if the memo's value and `changed_at` time is still valid in this revision. - /// Does only a shallow O(1) check, doesn't walk the dependencies. - #[inline] - pub(super) fn shallow_verify_memo( - &self, - db: &DynDb, - runtime: &Runtime, - database_key_index: DatabaseKeyIndex, - memo: &Memo, - ) -> bool { - let verified_at = memo.verified_at.load(); - let revision_now = runtime.current_revision(); - - log::debug!( - "{:?}: shallow_verify_memo(memo = {:#?})", - database_key_index.debug(db), - memo, - ); - - if verified_at == revision_now { - // Already verified. - return true; - } - - if memo.check_durability(runtime) { - // No input of the suitable durability has changed since last verified. - memo.mark_as_verified(db.as_salsa_database(), runtime, database_key_index); - return true; - } - - false - } - - /// True if the memo's value and `changed_at` time is up to date in the current - /// revision. When this returns true, it also updates the memo's `verified_at` - /// field if needed to make future calls cheaper. - /// - /// Takes an [`ActiveQueryGuard`] argument because this function recursively - /// walks dependencies of `old_memo` and may even execute them to see if their - /// outputs have changed. As that could lead to cycles, it is important that the - /// query is on the stack. - pub(super) fn deep_verify_memo( - &self, - db: &DynDb, - old_memo: &Memo, - active_query: &ActiveQueryGuard<'_>, - ) -> bool { - let runtime = db.runtime(); - let database_key_index = active_query.database_key_index; - - log::debug!( - "{:?}: deep_verify_memo(old_memo = {:#?})", - database_key_index.debug(db), - old_memo - ); - - if self.shallow_verify_memo(db, runtime, database_key_index, old_memo) { - return true; - } - - match &old_memo.revisions.origin { - QueryOrigin::Assigned(_) => { - // If the value was assigneed by another query, - // and that query were up-to-date, - // then we would have updated the `verified_at` field already. - // So the fact that we are here means that it was not specified - // during this revision or is otherwise stale. - return false; - } - QueryOrigin::BaseInput => { - // This value was `set` by the mutator thread -- ie, it's a base input and it cannot be out of date. - return true; - } - QueryOrigin::DerivedUntracked(_) => { - // Untracked inputs? Have to assume that it changed. - return false; - } - QueryOrigin::Derived(edges) => { - // Fully tracked inputs? Iterate over the inputs and check them, one by one. - // - // NB: It's important here that we are iterating the inputs in the order that - // they executed. It's possible that if the value of some input I0 is no longer - // valid, then some later input I1 might never have executed at all, so verifying - // it is still up to date is meaningless. - let last_verified_at = old_memo.verified_at.load(); - for &(edge_kind, dependency_index) in edges.input_outputs.iter() { - match edge_kind { - EdgeKind::Input => { - if db.maybe_changed_after(dependency_index, last_verified_at) { - return false; - } - } - EdgeKind::Output => { - // Subtle: Mark outputs as validated now, even though we may - // later find an input that requires us to re-execute the function. - // Even if it re-execute, the function will wind up writing the same value, - // since all prior inputs were green. It's important to do this during - // this loop, because it's possible that one of our input queries will - // re-execute and may read one of our earlier outputs - // (e.g., in a scenario where we do something like - // `e = Entity::new(..); query(e);` and `query` reads a field of `e`). - // - // NB. Accumulators are also outputs, but the above logic doesn't - // quite apply to them. Since multiple values are pushed, the first value - // may be unchanged, but later values could be different. - // In that case, however, the data accumulated - // by this function cannot be read until this function is marked green, - // so even if we mark them as valid here, the function will re-execute - // and overwrite the contents. - db.mark_validated_output(database_key_index, dependency_index); - } - } - } - } - } - - old_memo.mark_as_verified(db.as_salsa_database(), runtime, database_key_index); - true - } -} diff --git a/third-party/vendor/salsa-2022/src/function/memo.rs b/third-party/vendor/salsa-2022/src/function/memo.rs deleted file mode 100644 index 7c77ce8c..00000000 --- a/third-party/vendor/salsa-2022/src/function/memo.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::sync::Arc; - -use arc_swap::{ArcSwap, Guard}; -use crossbeam_utils::atomic::AtomicCell; - -use crate::{ - hash::FxDashMap, key::DatabaseKeyIndex, runtime::local_state::QueryRevisions, AsId, Event, - EventKind, Revision, Runtime, -}; - -/// The memo map maps from a key of type `K` to the memoized value for that `K`. -/// The memoized value is a `Memo` which contains, in addition to the value `V`, -/// dependency information. -pub(super) struct MemoMap { - map: FxDashMap>>, -} - -impl Default for MemoMap { - fn default() -> Self { - Self { - map: Default::default(), - } - } -} - -impl MemoMap { - /// Inserts the memo for the given key; (atomically) overwrites any previously existing memo.- - #[must_use] - pub(super) fn insert(&self, key: K, memo: Arc>) -> Option>> { - self.map.insert(key, ArcSwap::from(memo)) - } - - /// Removes any existing memo for the given key. - #[must_use] - pub(super) fn remove(&self, key: K) -> Option>> { - self.map.remove(&key).map(|o| o.1) - } - - /// Loads the current memo for `key_index`. This does not hold any sort of - /// lock on the `memo_map` once it returns, so this memo could immediately - /// become outdated if other threads store into the `memo_map`. - pub(super) fn get(&self, key: K) -> Option>>> { - self.map.get(&key).map(|v| v.load()) - } - - /// Evicts the existing memo for the given key, replacing it - /// with an equivalent memo that has no value. If the memo is untracked, BaseInput, - /// or has values assigned as output of another query, this has no effect. - pub(super) fn evict(&self, key: K) { - use crate::runtime::local_state::QueryOrigin; - use dashmap::mapref::entry::Entry::*; - - if let Occupied(entry) = self.map.entry(key) { - let memo = entry.get().load(); - match memo.revisions.origin { - QueryOrigin::Assigned(_) - | QueryOrigin::DerivedUntracked(_) - | QueryOrigin::BaseInput => { - // Careful: Cannot evict memos whose values were - // assigned as output of another query - // or those with untracked inputs - // as their values cannot be reconstructed. - } - - QueryOrigin::Derived(_) => { - let memo_evicted = Arc::new(Memo::new( - None::, - memo.verified_at.load(), - memo.revisions.clone(), - )); - - entry.get().store(memo_evicted); - } - } - } - } -} - -#[derive(Debug)] -pub(super) struct Memo { - /// The result of the query, if we decide to memoize it. - pub(super) value: Option, - - /// Last revision when this memo was verified; this begins - /// as the current revision. - pub(super) verified_at: AtomicCell, - - /// Revision information - pub(super) revisions: QueryRevisions, -} - -impl Memo { - pub(super) fn new(value: Option, revision_now: Revision, revisions: QueryRevisions) -> Self { - Memo { - value, - verified_at: AtomicCell::new(revision_now), - revisions, - } - } - /// True if this memo is known not to have changed based on its durability. - pub(super) fn check_durability(&self, runtime: &Runtime) -> bool { - let last_changed = runtime.last_changed_revision(self.revisions.durability); - let verified_at = self.verified_at.load(); - log::debug!( - "check_durability(last_changed={:?} <= verified_at={:?}) = {:?}", - last_changed, - self.verified_at, - last_changed <= verified_at, - ); - last_changed <= verified_at - } - - /// Mark memo as having been verified in the `revision_now`, which should - /// be the current revision. - pub(super) fn mark_as_verified( - &self, - db: &dyn crate::Database, - runtime: &crate::Runtime, - database_key_index: DatabaseKeyIndex, - ) { - db.salsa_event(Event { - runtime_id: runtime.id(), - kind: EventKind::DidValidateMemoizedValue { - database_key: database_key_index, - }, - }); - - self.verified_at.store(runtime.current_revision()); - - // Also mark the outputs as verified - for output in self.revisions.origin.outputs() { - db.mark_validated_output(database_key_index, output); - } - } -} diff --git a/third-party/vendor/salsa-2022/src/function/specify.rs b/third-party/vendor/salsa-2022/src/function/specify.rs deleted file mode 100644 index 1904cc63..00000000 --- a/third-party/vendor/salsa-2022/src/function/specify.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crossbeam::atomic::AtomicCell; - -use crate::{ - database::AsSalsaDatabase, - runtime::local_state::{QueryOrigin, QueryRevisions}, - storage::HasJarsDyn, - tracked_struct::TrackedStructInDb, - DatabaseKeyIndex, DebugWithDb, -}; - -use super::{memo::Memo, Configuration, DynDb, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - /// Specifies the value of the function for the given key. - /// This is a way to imperatively set the value of a function. - /// It only works if the key is a tracked struct created in the current query. - pub(crate) fn specify<'db>( - &self, - db: &'db DynDb<'db, C>, - key: C::Key, - value: C::Value, - origin: impl Fn(DatabaseKeyIndex) -> QueryOrigin, - ) where - C::Key: TrackedStructInDb>, - { - let runtime = db.runtime(); - - let (active_query_key, current_deps) = match runtime.active_query() { - Some(v) => v, - None => panic!("can only use `specify` with an active query"), - }; - - // `specify` only works if the key is a tracked struct created in the current query. - // - // The reason is this. We want to ensure that the same result is reached regardless of - // the "path" that the user takes through the execution graph. - // If you permit values to be specified from other queries, you can have a situation like this: - // * Q0 creates the tracked struct T0 - // * Q1 specifies the value for F(T0) - // * Q2 invokes F(T0) - // * Q3 invokes Q1 and then Q2 - // * Q4 invokes Q2 and then Q1 - // - // Now, if We invoke Q3 first, We get one result for Q2, but if We invoke Q4 first, We get a different value. That's no good. - let database_key_index = key.database_key_index(db); - let dependency_index = database_key_index.into(); - if !runtime.is_output_of_active_query(dependency_index) { - panic!("can only use `specfiy` on entities created during current query"); - } - - // Subtle: we treat the "input" to a set query as if it were - // volatile. - // - // The idea is this. You have the current query C that - // created the entity E, and it is setting the value F(E) of the function F. - // When some other query R reads the field F(E), in order to have obtained - // the entity E, it has to have executed the query C. - // - // This will have forced C to either: - // - // - not create E this time, in which case R shouldn't have it (some kind of leak has occurred) - // - assign a value to F(E), in which case `verified_at` will be the current revision and `changed_at` will be updated appropriately - // - NOT assign a value to F(E), in which case we need to re-execute the function (which typically panics). - // - // So, ruling out the case of a leak having occurred, that means that the reader R will either see: - // - // - a result that is verified in the current revision, because it was set, which will use the set value - // - a result that is NOT verified and has untracked inputs, which will re-execute (and likely panic) - - let revision = runtime.current_revision(); - let mut revisions = QueryRevisions { - changed_at: current_deps.changed_at, - durability: current_deps.durability, - origin: origin(active_query_key), - }; - - if let Some(old_memo) = self.memo_map.get(key) { - self.backdate_if_appropriate(&old_memo, &mut revisions, &value); - self.diff_outputs(db, database_key_index, &old_memo, &revisions); - } - - let memo = Memo { - value: Some(value), - verified_at: AtomicCell::new(revision), - revisions, - }; - - log::debug!("specify: about to add memo {:#?} for key {:?}", memo, key); - self.insert_memo(db, key, memo); - } - - /// Specify the value for `key` *and* record that we did so. - /// Used for explicit calls to `specify`, but not needed for pre-declared tracked struct fields. - pub fn specify_and_record<'db>(&self, db: &'db DynDb<'db, C>, key: C::Key, value: C::Value) - where - C::Key: TrackedStructInDb>, - { - self.specify(db, key, value, |database_key_index| { - QueryOrigin::Assigned(database_key_index) - }); - - // Record that the current query *specified* a value for this cell. - let database_key_index = self.database_key_index(key); - db.runtime().add_output(database_key_index.into()); - } - - /// Invoked when the query `executor` has been validated as having green inputs - /// and `key` is a value that was specified by `executor`. - /// Marks `key` as valid in the current revision since if `executor` had re-executed, - /// it would have specified `key` again. - pub(super) fn validate_specified_value( - &self, - db: &DynDb<'_, C>, - executor: DatabaseKeyIndex, - key: C::Key, - ) { - let runtime = db.runtime(); - - let memo = match self.memo_map.get(key) { - Some(m) => m, - None => return, - }; - - // If we are marking this as validated, it must be a value that was - // assigneed by `executor`. - match memo.revisions.origin { - QueryOrigin::Assigned(by_query) => assert_eq!(by_query, executor), - _ => panic!( - "expected a query assigned by `{:?}`, not `{:?}`", - executor.debug(db), - memo.revisions.origin, - ), - } - - let database_key_index = self.database_key_index(key); - memo.mark_as_verified(db.as_salsa_database(), runtime, database_key_index); - } -} diff --git a/third-party/vendor/salsa-2022/src/function/store.rs b/third-party/vendor/salsa-2022/src/function/store.rs deleted file mode 100644 index a90b1245..00000000 --- a/third-party/vendor/salsa-2022/src/function/store.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::sync::Arc; - -use crossbeam::atomic::AtomicCell; - -use crate::{ - durability::Durability, - runtime::local_state::{QueryOrigin, QueryRevisions}, - Runtime, -}; - -use super::{memo::Memo, Configuration, FunctionIngredient}; - -impl FunctionIngredient -where - C: Configuration, -{ - pub fn store( - &mut self, - runtime: &mut Runtime, - key: C::Key, - value: C::Value, - durability: Durability, - ) { - let revision = runtime.current_revision(); - let memo = Memo { - value: Some(value), - verified_at: AtomicCell::new(revision), - revisions: QueryRevisions { - changed_at: revision, - durability, - origin: QueryOrigin::BaseInput, - }, - }; - - if let Some(old_value) = self.memo_map.insert(key, Arc::new(memo)) { - // NB: we don't have to store `old_value` into `deleted_entries` because we have `&mut self`. - let durability = old_value.load().revisions.durability; - runtime.report_tracked_write(durability); - } - } -} diff --git a/third-party/vendor/salsa-2022/src/function/sync.rs b/third-party/vendor/salsa-2022/src/function/sync.rs deleted file mode 100644 index aa63e3d8..00000000 --- a/third-party/vendor/salsa-2022/src/function/sync.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::sync::atomic::{AtomicBool, Ordering}; - -use crate::{ - hash::FxDashMap, - key::DatabaseKeyIndex, - runtime::{RuntimeId, WaitResult}, - Database, Id, Runtime, -}; - -#[derive(Default)] -pub(super) struct SyncMap { - sync_map: FxDashMap, -} - -struct SyncState { - id: RuntimeId, - - /// Set to true if any other queries are blocked, - /// waiting for this query to complete. - anyone_waiting: AtomicBool, -} - -impl SyncMap { - pub(super) fn claim<'me>( - &'me self, - db: &'me dyn Database, - database_key_index: DatabaseKeyIndex, - ) -> Option> { - let runtime = db.runtime(); - match self.sync_map.entry(database_key_index.key_index) { - dashmap::mapref::entry::Entry::Vacant(entry) => { - entry.insert(SyncState { - id: runtime.id(), - anyone_waiting: AtomicBool::new(false), - }); - Some(ClaimGuard { - database_key: database_key_index, - runtime, - sync_map: &self.sync_map, - }) - } - dashmap::mapref::entry::Entry::Occupied(entry) => { - // NB: `Ordering::Relaxed` is sufficient here, - // as there are no loads that are "gated" on this - // value. Everything that is written is also protected - // by a lock that must be acquired. The role of this - // boolean is to decide *whether* to acquire the lock, - // not to gate future atomic reads. - entry.get().anyone_waiting.store(true, Ordering::Relaxed); - let other_id = entry.get().id; - runtime.block_on_or_unwind(db, database_key_index, other_id, entry); - None - } - } - } -} - -/// Marks an active 'claim' in the synchronization map. The claim is -/// released when this value is dropped. -#[must_use] -pub(super) struct ClaimGuard<'me> { - database_key: DatabaseKeyIndex, - runtime: &'me Runtime, - sync_map: &'me FxDashMap, -} - -impl<'me> ClaimGuard<'me> { - fn remove_from_map_and_unblock_queries(&self, wait_result: WaitResult) { - let (_, SyncState { anyone_waiting, .. }) = - self.sync_map.remove(&self.database_key.key_index).unwrap(); - - // NB: `Ordering::Relaxed` is sufficient here, - // see `store` above for explanation. - if anyone_waiting.load(Ordering::Relaxed) { - self.runtime - .unblock_queries_blocked_on(self.database_key, wait_result) - } - } -} - -impl<'me> Drop for ClaimGuard<'me> { - fn drop(&mut self) { - let wait_result = if std::thread::panicking() { - WaitResult::Panicked - } else { - WaitResult::Completed - }; - self.remove_from_map_and_unblock_queries(wait_result) - } -} diff --git a/third-party/vendor/salsa-2022/src/hash.rs b/third-party/vendor/salsa-2022/src/hash.rs deleted file mode 100644 index 9d6a708e..00000000 --- a/third-party/vendor/salsa-2022/src/hash.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::hash::{BuildHasher, Hash, Hasher}; - -pub(crate) type FxHasher = std::hash::BuildHasherDefault; -pub(crate) type FxIndexSet = indexmap::IndexSet; -pub(crate) type FxIndexMap = indexmap::IndexMap; -pub(crate) type FxDashMap = dashmap::DashMap; -pub(crate) type FxLinkedHashSet = hashlink::LinkedHashSet; -pub(crate) type FxHashSet = std::collections::HashSet; - -pub(crate) fn hash(t: &T) -> u64 { - let mut hasher = FxHasher::default().build_hasher(); - t.hash(&mut hasher); - hasher.finish() -} diff --git a/third-party/vendor/salsa-2022/src/id.rs b/third-party/vendor/salsa-2022/src/id.rs deleted file mode 100644 index c1db29b3..00000000 --- a/third-party/vendor/salsa-2022/src/id.rs +++ /dev/null @@ -1,94 +0,0 @@ -use std::fmt::Debug; -use std::hash::Hash; -use std::num::NonZeroU32; - -/// An Id is a newtype'd u32 ranging from `0..Id::MAX_U32`. -/// The maximum range is smaller than a standard u32 to leave -/// room for niches; currently there is only one niche, so that -/// `Option` is the same size as an `Id`. -/// -/// You will rarely use the `Id` type directly, though you can. -/// You are more likely to use types that implement the `AsId` trait, -/// such as entity keys. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct Id { - value: NonZeroU32, -} - -impl Id { - pub const MAX_U32: u32 = std::u32::MAX - 0xFF; - pub const MAX_USIZE: usize = Self::MAX_U32 as usize; - - /// Create a `salsa::Id` from a u32 value. This value should - /// be less than [`Self::MAX_U32`]. - /// - /// In general, you should not need to create salsa ids yourself, - /// but it can be useful if you are using the type as a general - /// purpose "identifier" internally. - #[track_caller] - pub const fn from_u32(x: u32) -> Self { - Id { - value: match NonZeroU32::new(x + 1) { - Some(v) => v, - None => panic!("given value is too large to be a `salsa::Id`"), - }, - } - } - - pub const fn as_u32(self) -> u32 { - self.value.get() - 1 - } -} - -impl From for Id { - fn from(n: u32) -> Self { - Id::from_u32(n) - } -} - -impl From for Id { - fn from(n: usize) -> Self { - assert!(n < Id::MAX_USIZE); - Id::from_u32(n as u32) - } -} - -impl From for u32 { - fn from(n: Id) -> Self { - n.as_u32() - } -} - -impl From for usize { - fn from(n: Id) -> usize { - n.as_u32() as usize - } -} - -/// Trait for types that can be interconverted to a salsa Id; -pub trait AsId: Sized + Copy + Eq + Hash + Debug { - fn as_id(self) -> Id; - fn from_id(id: Id) -> Self; -} - -impl AsId for Id { - fn as_id(self) -> Id { - self - } - - fn from_id(id: Id) -> Self { - id - } -} - -/// As a special case, we permit `()` to be converted to an `Id`. -/// This is useful for declaring functions with no arguments. -impl AsId for () { - fn as_id(self) -> Id { - Id::from_u32(0) - } - - fn from_id(id: Id) -> Self { - assert_eq!(0, id.as_u32()); - } -} diff --git a/third-party/vendor/salsa-2022/src/ingredient.rs b/third-party/vendor/salsa-2022/src/ingredient.rs deleted file mode 100644 index dc8f2b90..00000000 --- a/third-party/vendor/salsa-2022/src/ingredient.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::fmt; - -use crate::{ - cycle::CycleRecoveryStrategy, key::DependencyIndex, runtime::local_state::QueryOrigin, - DatabaseKeyIndex, Id, IngredientIndex, -}; - -use super::Revision; - -/// "Ingredients" are the bits of data that are stored within the database to make salsa work. -/// Each jar will define some number of ingredients that it requires. -/// Each use salsa macro (e.g., `#[salsa::tracked]`, `#[salsa::interned]`) adds one or more -/// ingredients to the jar struct that together are used to create the salsa concept. -/// For example, a tracked struct defines a [`crate::interned::InternedIngredient`] to store -/// its identity plus [`crate::function::FunctionIngredient`] values to store its fields. -/// The exact ingredients are determined by -/// [`IngredientsFor`](`crate::storage::IngredientsFor`) implementations generated by the -/// macro. -pub trait Ingredient { - /// Returns the [`IngredientIndex`] of this ingredient. - fn ingredient_index(&self) -> IngredientIndex; - - /// If this ingredient is a participant in a cycle, what is its cycle recovery strategy? - /// (Really only relevant to [`crate::function::FunctionIngredient`], - /// since only function ingredients push themselves onto the active query stack.) - fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy; - - /// Has the value for `input` in this ingredient changed after `revision`? - fn maybe_changed_after(&self, db: &DB, input: DependencyIndex, revision: Revision) -> bool; - - /// What were the inputs (if any) that were used to create the value at `key_index`. - fn origin(&self, key_index: Id) -> Option; - - /// Invoked when the value `output_key` should be marked as valid in the current revision. - /// This occurs because the value for `executor`, which generated it, was marked as valid - /// in the current revision. - fn mark_validated_output(&self, db: &DB, executor: DatabaseKeyIndex, output_key: Option); - - /// Invoked when the value `stale_output` was output by `executor` in a previous - /// revision, but was NOT output in the current revision. - /// - /// This hook is used to clear out the stale value so others cannot read it. - fn remove_stale_output( - &self, - db: &DB, - executor: DatabaseKeyIndex, - stale_output_key: Option, - ); - - /// Informs the ingredient `self` that the salsa struct with id `id` has been deleted. - /// This gives `self` a chance to remove any memoized data dependent on `id`. - /// To receive this callback, `self` must register itself as a dependent function using - /// [`SalsaStructInDb::register_dependent_fn`](`crate::salsa_struct::SalsaStructInDb::register_dependent_fn`). - fn salsa_struct_deleted(&self, db: &DB, id: Id); - - /// Invoked when a new revision is about to start. - /// This moment is important because it means that we have an `&mut`-reference to the - /// database, and hence any pre-existing `&`-references must have expired. - /// Many ingredients, given an `&'db`-reference to the database, - /// use unsafe code to return `&'db`-references to internal values. - /// The backing memory for those values can only be freed once an `&mut`-reference to the - /// database is created. - /// - /// **Important:** to actually receive resets, the ingredient must set - /// [`IngredientRequiresReset::RESET_ON_NEW_REVISION`] to true. - fn reset_for_new_revision(&mut self); - - fn fmt_index(&self, index: Option, fmt: &mut fmt::Formatter<'_>) -> fmt::Result; -} - -/// A helper function to show human readable fmt. -pub(crate) fn fmt_index( - debug_name: &str, - id: Option, - fmt: &mut fmt::Formatter<'_>, -) -> fmt::Result { - if let Some(i) = id { - write!(fmt, "{}({})", debug_name, u32::from(i)) - } else { - write!(fmt, "{}()", debug_name) - } -} - -/// Defines a const indicating if an ingredient needs to be reset each round. -/// This const probably *should* be a member of `Ingredient` trait but then `Ingredient` would -/// not be dyn-safe. -pub trait IngredientRequiresReset { - /// If this is true, then `reset_for_new_revision` will be called every new revision. - const RESET_ON_NEW_REVISION: bool; -} diff --git a/third-party/vendor/salsa-2022/src/ingredient_list.rs b/third-party/vendor/salsa-2022/src/ingredient_list.rs deleted file mode 100644 index f80c41ad..00000000 --- a/third-party/vendor/salsa-2022/src/ingredient_list.rs +++ /dev/null @@ -1,83 +0,0 @@ -use std::sync::Arc; - -use arc_swap::{ArcSwapOption, AsRaw}; - -use crate::IngredientIndex; - -/// A list of ingredients that can be added to in parallel. -pub(crate) struct IngredientList { - /// A list of each tracked functions. - /// tracked struct. - /// - /// Whenever an instance `i` of this struct is deleted, - /// each of these functions will be notified - /// so they can remove any data tied to that instance. - list: ArcSwapOption>, -} - -impl IngredientList { - pub fn new() -> Self { - Self { - list: ArcSwapOption::new(None), - } - } - - /// Returns an iterator over the items in the list. - /// This is a snapshot of the list as it was when this function is called. - /// Items could still be added in parallel via `add_ingredient` - /// that will not be returned by this iterator. - pub(crate) fn iter(&self) -> impl Iterator { - let guard = self.list.load(); - let mut index = 0; - std::iter::from_fn(move || match &*guard { - Some(list) if index < list.len() => { - let r = list[index]; - index += 1; - Some(r) - } - _ => None, - }) - } - - /// Adds an ingredient to the list (if not already present). - pub(crate) fn push(&self, index: IngredientIndex) { - // This function is called whenever a value is stored, - // so other tracked functions and things may be executing, - // and there could even be two calls to this function in parallel. - // - // We use a "compare-and-swap" strategy of reading the old vector, creating a new vector, - // and then installing it, hoping that nobody has conflicted with us. - // If that fails, we start over. - - loop { - let guard = self.list.load(); - let empty_vec = vec![]; - let old_vec = match &*guard { - Some(v) => v, - None => &empty_vec, - }; - - // First check whether the index is already present. - if old_vec.contains(&index) { - return; - } - - // If not, construct a new vector that has all the old values, followed by `index`. - let vec: Arc> = Arc::new( - old_vec - .iter() - .copied() - .chain(std::iter::once(index)) - .collect(), - ); - - // Try to replace the old vector with the new one. If we fail, loop around again. - assert_eq!(vec.len(), vec.capacity()); - let previous = self.list.compare_and_swap(&guard, Some(vec)); - if guard.as_raw() == previous.as_raw() { - // swap was successful - break; - } - } - } -} diff --git a/third-party/vendor/salsa-2022/src/input.rs b/third-party/vendor/salsa-2022/src/input.rs deleted file mode 100644 index 6c6900c0..00000000 --- a/third-party/vendor/salsa-2022/src/input.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::{ - fmt, - sync::atomic::{AtomicU32, Ordering}, -}; - -use crate::{ - cycle::CycleRecoveryStrategy, - ingredient::{fmt_index, Ingredient, IngredientRequiresReset}, - key::{DatabaseKeyIndex, DependencyIndex}, - runtime::{local_state::QueryOrigin, Runtime}, - AsId, IngredientIndex, Revision, -}; - -pub trait InputId: AsId {} -impl InputId for T {} - -pub struct InputIngredient -where - Id: InputId, -{ - ingredient_index: IngredientIndex, - counter: AtomicU32, - debug_name: &'static str, - _phantom: std::marker::PhantomData, -} - -impl InputIngredient -where - Id: InputId, -{ - pub fn new(index: IngredientIndex, debug_name: &'static str) -> Self { - Self { - ingredient_index: index, - counter: Default::default(), - debug_name, - _phantom: std::marker::PhantomData, - } - } - - pub fn database_key_index(&self, id: Id) -> DatabaseKeyIndex { - DatabaseKeyIndex { - ingredient_index: self.ingredient_index, - key_index: id.as_id(), - } - } - - pub fn new_input(&self, _runtime: &Runtime) -> Id { - let next_id = self.counter.fetch_add(1, Ordering::Relaxed); - Id::from_id(crate::Id::from_u32(next_id)) - } - - pub fn new_singleton_input(&self, _runtime: &Runtime) -> Id { - // when one exists already, panic - if self.counter.load(Ordering::Relaxed) >= 1 { - panic!("singleton struct may not be duplicated"); - } - // fresh new ingredient - self.counter.store(1, Ordering::Relaxed); - Id::from_id(crate::Id::from_u32(0)) - } - - pub fn get_singleton_input(&self, _runtime: &Runtime) -> Option { - (self.counter.load(Ordering::Relaxed) > 0).then(|| Id::from_id(crate::Id::from_u32(0))) - } -} - -impl Ingredient for InputIngredient -where - Id: InputId, -{ - fn ingredient_index(&self) -> IngredientIndex { - self.ingredient_index - } - - fn maybe_changed_after(&self, _db: &DB, _input: DependencyIndex, _revision: Revision) -> bool { - // Input ingredients are just a counter, they store no data, they are immortal. - // Their *fields* are stored in function ingredients elsewhere. - false - } - - fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy { - CycleRecoveryStrategy::Panic - } - - fn origin(&self, _key_index: crate::Id) -> Option { - None - } - - fn mark_validated_output( - &self, - _db: &DB, - executor: DatabaseKeyIndex, - output_key: Option, - ) { - unreachable!( - "mark_validated_output({:?}, {:?}): input cannot be the output of a tracked function", - executor, output_key - ); - } - - fn remove_stale_output( - &self, - _db: &DB, - executor: DatabaseKeyIndex, - stale_output_key: Option, - ) { - unreachable!( - "remove_stale_output({:?}, {:?}): input cannot be the output of a tracked function", - executor, stale_output_key - ); - } - - fn reset_for_new_revision(&mut self) { - panic!("unexpected call to `reset_for_new_revision`") - } - - fn salsa_struct_deleted(&self, _db: &DB, _id: crate::Id) { - panic!( - "unexpected call: input ingredients do not register for salsa struct deletion events" - ); - } - - fn fmt_index(&self, index: Option, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_index(self.debug_name, index, fmt) - } -} - -impl IngredientRequiresReset for InputIngredient -where - Id: InputId, -{ - const RESET_ON_NEW_REVISION: bool = false; -} diff --git a/third-party/vendor/salsa-2022/src/input_field.rs b/third-party/vendor/salsa-2022/src/input_field.rs deleted file mode 100644 index fcd9c706..00000000 --- a/third-party/vendor/salsa-2022/src/input_field.rs +++ /dev/null @@ -1,170 +0,0 @@ -use crate::cycle::CycleRecoveryStrategy; -use crate::ingredient::{fmt_index, Ingredient, IngredientRequiresReset}; -use crate::key::DependencyIndex; -use crate::runtime::local_state::QueryOrigin; -use crate::runtime::StampedValue; -use crate::{AsId, DatabaseKeyIndex, Durability, Id, IngredientIndex, Revision, Runtime}; -use dashmap::mapref::entry::Entry; -use dashmap::DashMap; -use std::fmt; -use std::hash::Hash; - -/// Ingredient used to represent the fields of a `#[salsa::input]`. -/// -/// These fields can only be mutated by a call to a setter with an `&mut` -/// reference to the database, and therefore cannot be mutated during a tracked -/// function or in parallel. -/// However for on-demand inputs to work the fields must be able to be set via -/// a shared reference, so some locking is required. -/// Altogether this makes the implementation somewhat simpler than tracked -/// structs. -pub struct InputFieldIngredient { - index: IngredientIndex, - map: DashMap>>, - debug_name: &'static str, -} - -impl InputFieldIngredient -where - K: Eq + Hash + AsId, -{ - pub fn new(index: IngredientIndex, debug_name: &'static str) -> Self { - Self { - index, - map: Default::default(), - debug_name, - } - } - - pub fn store_mut( - &mut self, - runtime: &Runtime, - key: K, - value: F, - durability: Durability, - ) -> Option { - let revision = runtime.current_revision(); - let stamped_value = Box::new(StampedValue { - value, - durability, - changed_at: revision, - }); - - self.map - .insert(key, stamped_value) - .map(|old_value| old_value.value) - } - - /// Set the field of a new input. - /// - /// This function panics if the field has ever been set before. - pub fn store_new(&self, runtime: &Runtime, key: K, value: F, durability: Durability) { - let revision = runtime.current_revision(); - let stamped_value = Box::new(StampedValue { - value, - durability, - changed_at: revision, - }); - - match self.map.entry(key) { - Entry::Occupied(_) => { - panic!("attempted to set field of existing input using `store_new`, use `store_mut` instead"); - } - Entry::Vacant(entry) => { - entry.insert(stamped_value); - } - } - } - - pub fn fetch<'db>(&'db self, runtime: &'db Runtime, key: K) -> &F { - let StampedValue { - value, - durability, - changed_at, - } = &**self.map.get(&key).unwrap(); - - runtime.report_tracked_read( - self.database_key_index(key).into(), - *durability, - *changed_at, - ); - - // SAFETY: - // The value is stored in a box so internal moves in the dashmap don't - // invalidate the reference to the value inside the box. - // Values are only removed or altered when we have `&mut self`. - unsafe { transmute_lifetime(self, value) } - } - - fn database_key_index(&self, key: K) -> DatabaseKeyIndex { - DatabaseKeyIndex { - ingredient_index: self.index, - key_index: key.as_id(), - } - } -} - -// Returns `u` but with the lifetime of `t`. -// -// Safe if you know that data at `u` will remain shared -// until the reference `t` expires. -unsafe fn transmute_lifetime<'t, 'u, T, U>(_t: &'t T, u: &'u U) -> &'t U { - std::mem::transmute(u) -} - -impl Ingredient for InputFieldIngredient -where - K: AsId, -{ - fn ingredient_index(&self) -> IngredientIndex { - self.index - } - - fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy { - CycleRecoveryStrategy::Panic - } - - fn maybe_changed_after(&self, _db: &DB, input: DependencyIndex, revision: Revision) -> bool { - let key = K::from_id(input.key_index.unwrap()); - self.map.get(&key).unwrap().changed_at > revision - } - - fn origin(&self, _key_index: Id) -> Option { - None - } - - fn mark_validated_output( - &self, - _db: &DB, - _executor: DatabaseKeyIndex, - _output_key: Option, - ) { - } - - fn remove_stale_output( - &self, - _db: &DB, - _executor: DatabaseKeyIndex, - _stale_output_key: Option, - ) { - } - - fn salsa_struct_deleted(&self, _db: &DB, _id: Id) { - panic!("unexpected call: input fields are never deleted"); - } - - fn reset_for_new_revision(&mut self) { - panic!("unexpected call: input fields don't register for resets"); - } - - fn fmt_index(&self, index: Option, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_index(self.debug_name, index, fmt) - } -} - -impl IngredientRequiresReset for InputFieldIngredient -where - K: AsId, -{ - const RESET_ON_NEW_REVISION: bool = false; -} diff --git a/third-party/vendor/salsa-2022/src/interned.rs b/third-party/vendor/salsa-2022/src/interned.rs deleted file mode 100644 index 80d78f87..00000000 --- a/third-party/vendor/salsa-2022/src/interned.rs +++ /dev/null @@ -1,278 +0,0 @@ -use crossbeam::atomic::AtomicCell; -use crossbeam::queue::SegQueue; -use std::fmt; -use std::hash::Hash; -use std::marker::PhantomData; - -use crate::durability::Durability; -use crate::id::AsId; -use crate::ingredient::{fmt_index, IngredientRequiresReset}; -use crate::key::DependencyIndex; -use crate::runtime::local_state::QueryOrigin; -use crate::runtime::Runtime; -use crate::DatabaseKeyIndex; - -use super::hash::FxDashMap; -use super::ingredient::Ingredient; -use super::routes::IngredientIndex; -use super::Revision; - -pub trait InternedId: AsId {} -impl InternedId for T {} - -pub trait InternedData: Sized + Eq + Hash + Clone {} -impl InternedData for T {} - -/// The interned ingredient has the job of hashing values of type `Data` to produce an `Id`. -/// It used to store interned structs but also to store the id fields of a tracked struct. -/// Interned values endure until they are explicitly removed in some way. -pub struct InternedIngredient { - /// Index of this ingredient in the database (used to construct database-ids, etc). - ingredient_index: IngredientIndex, - - /// Maps from data to the existing interned id for that data. - /// - /// Deadlock requirement: We access `value_map` while holding lock on `key_map`, but not vice versa. - key_map: FxDashMap, - - /// Maps from an interned id to its data. - /// - /// Deadlock requirement: We access `value_map` while holding lock on `key_map`, but not vice versa. - value_map: FxDashMap>, - - /// counter for the next id. - counter: AtomicCell, - - /// Stores the revision when this interned ingredient was last cleared. - /// You can clear an interned table at any point, deleting all its entries, - /// but that will make anything dependent on those entries dirty and in need - /// of being recomputed. - reset_at: Revision, - - /// When specific entries are deleted from the interned table, their data is added - /// to this vector rather than being immediately freed. This is because we may` have - /// references to that data floating about that are tied to the lifetime of some - /// `&db` reference. This queue itself is not freed until we have an `&mut db` reference, - /// guaranteeing that there are no more references to it. - deleted_entries: SegQueue>, - - debug_name: &'static str, -} - -impl InternedIngredient -where - Id: InternedId, - Data: InternedData, -{ - pub fn new(ingredient_index: IngredientIndex, debug_name: &'static str) -> Self { - Self { - ingredient_index, - key_map: Default::default(), - value_map: Default::default(), - counter: AtomicCell::default(), - reset_at: Revision::start(), - deleted_entries: Default::default(), - debug_name, - } - } - - pub fn intern(&self, runtime: &Runtime, data: Data) -> Id { - runtime.report_tracked_read( - DependencyIndex::for_table(self.ingredient_index), - Durability::MAX, - self.reset_at, - ); - - // Optimisation to only get read lock on the map if the data has already - // been interned. - if let Some(id) = self.key_map.get(&data) { - return *id; - } - - match self.key_map.entry(data.clone()) { - // Data has been interned by a racing call, use that ID instead - dashmap::mapref::entry::Entry::Occupied(entry) => *entry.get(), - // We won any races so should intern the data - dashmap::mapref::entry::Entry::Vacant(entry) => { - let next_id = self.counter.fetch_add(1); - let next_id = Id::from_id(crate::id::Id::from_u32(next_id)); - let old_value = self.value_map.insert(next_id, Box::new(data)); - assert!( - old_value.is_none(), - "next_id is guaranteed to be unique, bar overflow" - ); - entry.insert(next_id); - next_id - } - } - } - - pub(crate) fn reset_at(&self) -> Revision { - self.reset_at - } - - pub fn reset(&mut self, revision: Revision) { - assert!(revision > self.reset_at); - self.reset_at = revision; - self.key_map.clear(); - self.value_map.clear(); - } - - #[track_caller] - pub fn data<'db>(&'db self, runtime: &'db Runtime, id: Id) -> &'db Data { - runtime.report_tracked_read( - DependencyIndex::for_table(self.ingredient_index), - Durability::MAX, - self.reset_at, - ); - - let data = match self.value_map.get(&id) { - Some(d) => d, - None => { - panic!("no data found for id `{:?}`", id) - } - }; - - // Unsafety clause: - // - // * Values are only removed or altered when we have `&mut self` - unsafe { transmute_lifetime(self, &**data) } - } - - /// Get the ingredient index for this table. - pub(super) fn ingredient_index(&self) -> IngredientIndex { - self.ingredient_index - } - - /// Deletes an index from the interning table, making it available for re-use. - /// - /// # Warning - /// - /// This should only be used when you are certain that: - /// 1. The given `id` has not (and will not) be used in the current revision. - /// 2. The interned data corresponding to `id` will not be interned in this revision. - /// - /// More specifically, this is used when a query `Q` executes and we can compare the - /// entities `E_now` that it produced in this revision vs the entities `E_prev` it - /// produced in the last revision. Any missing entities `E_prev - E_new` can be deleted. - /// - /// If you are wrong about this, it should not be unsafe, but unpredictable results may occur. - pub(crate) fn delete_index(&self, id: Id) { - let (_, key) = self - .value_map - .remove(&id) - .unwrap_or_else(|| panic!("No entry for id `{:?}`", id)); - - self.key_map.remove(&key); - // Careful: even though `id` ought not to have been used in this revision, - // we don't know that for sure since users could have leaked things. If they did, - // they may have stray references into `data`. So push the box onto the - // "to be deleted" queue. - // - // To avoid this, we could include some kind of atomic counter in the `Box` that - // gets set whenever `data` executes, so we can track if the data was accessed since - // the last time an `&mut self` method was called. But that'd take extra storage - // and doesn't obviously seem worth it. - self.deleted_entries.push(key); - } - - pub(crate) fn clear_deleted_indices(&mut self) { - std::mem::take(&mut self.deleted_entries); - } -} - -// Returns `u` but with the lifetime of `t`. -// -// Safe if you know that data at `u` will remain shared -// until the reference `t` expires. -unsafe fn transmute_lifetime<'t, 'u, T, U>(_t: &'t T, u: &'u U) -> &'t U { - std::mem::transmute(u) -} - -impl Ingredient for InternedIngredient -where - Id: InternedId, - Data: InternedData, -{ - fn ingredient_index(&self) -> IngredientIndex { - self.ingredient_index - } - - fn maybe_changed_after(&self, _db: &DB, _input: DependencyIndex, revision: Revision) -> bool { - revision < self.reset_at - } - - fn cycle_recovery_strategy(&self) -> crate::cycle::CycleRecoveryStrategy { - crate::cycle::CycleRecoveryStrategy::Panic - } - - fn origin(&self, _key_index: crate::Id) -> Option { - None - } - - fn mark_validated_output( - &self, - _db: &DB, - executor: DatabaseKeyIndex, - output_key: Option, - ) { - unreachable!( - "mark_validated_output({:?}, {:?}): input cannot be the output of a tracked function", - executor, output_key - ); - } - - fn remove_stale_output( - &self, - _db: &DB, - executor: DatabaseKeyIndex, - stale_output_key: Option, - ) { - unreachable!( - "remove_stale_output({:?}, {:?}): interned ids are not outputs", - executor, stale_output_key - ); - } - - fn reset_for_new_revision(&mut self) { - // Interned ingredients do not, normally, get deleted except when they are "reset" en masse. - // There ARE methods (e.g., `clear_deleted_entries` and `remove`) for deleting individual - // items, but those are only used for tracked struct ingredients. - panic!("unexpected call to `reset_for_new_revision`") - } - - fn salsa_struct_deleted(&self, _db: &DB, _id: crate::Id) { - panic!("unexpected call: interned ingredients do not register for salsa struct deletion events"); - } - - fn fmt_index(&self, index: Option, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_index(self.debug_name, index, fmt) - } -} - -impl IngredientRequiresReset for InternedIngredient -where - Id: InternedId, - Data: InternedData, -{ - const RESET_ON_NEW_REVISION: bool = false; -} - -pub struct IdentityInterner { - data: PhantomData, -} - -impl IdentityInterner { - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - IdentityInterner { data: PhantomData } - } - - pub fn intern(&self, _runtime: &Runtime, id: Id) -> Id { - id - } - - pub fn data(&self, _runtime: &Runtime, id: Id) -> (Id,) { - (id,) - } -} diff --git a/third-party/vendor/salsa-2022/src/jar.rs b/third-party/vendor/salsa-2022/src/jar.rs deleted file mode 100644 index 35c4438e..00000000 --- a/third-party/vendor/salsa-2022/src/jar.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::{ - storage::{HasJar, JarFromJars}, - Database, DbWithJar, -}; - -use super::routes::Routes; - -/// Representative trait of a salsa jar -/// -/// # Safety -/// -/// `init_jar` must fully initialize the jar -pub unsafe trait Jar<'db>: Sized { - type DynDb: ?Sized + HasJar + Database + 'db; - - /// Initializes the jar at `place` - /// - /// # Safety - /// - /// `place` must be a valid pointer to this jar - unsafe fn init_jar(place: *mut Self, routes: &mut Routes) - where - DB: JarFromJars + DbWithJar; -} diff --git a/third-party/vendor/salsa-2022/src/key.rs b/third-party/vendor/salsa-2022/src/key.rs deleted file mode 100644 index 8b71811d..00000000 --- a/third-party/vendor/salsa-2022/src/key.rs +++ /dev/null @@ -1,106 +0,0 @@ -use std::fmt::Debug; - -use crate::{Database, DebugWithDb, Id, IngredientIndex}; - -/// An integer that uniquely identifies a particular query instance within the -/// database. Used to track dependencies between queries. Fully ordered and -/// equatable but those orderings are arbitrary, and meant to be used only for -/// inserting into maps and the like. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct DependencyIndex { - pub(crate) ingredient_index: IngredientIndex, - pub(crate) key_index: Option, -} - -impl DependencyIndex { - /// Create a database-key-index for an interning or entity table. - /// The `key_index` here is always zero, which deliberately corresponds to - /// no particular id or entry. This is because the data in such tables - /// remains valid until the table as a whole is reset. Using a single id avoids - /// creating tons of dependencies in the dependency listings. - pub(crate) fn for_table(ingredient_index: IngredientIndex) -> Self { - Self { - ingredient_index, - key_index: None, - } - } - - pub fn ingredient_index(self) -> IngredientIndex { - self.ingredient_index - } - - pub fn key_index(self) -> Option { - self.key_index - } -} - -impl crate::debug::DebugWithDb for DependencyIndex -where - Db: ?Sized + Database, -{ - fn fmt( - &self, - f: &mut std::fmt::Formatter<'_>, - db: &Db, - _include_all_fields: bool, - ) -> std::fmt::Result { - db.fmt_index(*self, f) - } -} - -// ANCHOR: DatabaseKeyIndex -/// An "active" database key index represents a database key index -/// that is actively executing. In that case, the `key_index` cannot be -/// None. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct DatabaseKeyIndex { - pub(crate) ingredient_index: IngredientIndex, - pub(crate) key_index: Id, -} -// ANCHOR_END: DatabaseKeyIndex - -impl DatabaseKeyIndex { - pub fn ingredient_index(self) -> IngredientIndex { - self.ingredient_index - } - - pub fn key_index(self) -> Id { - self.key_index - } -} - -impl crate::debug::DebugWithDb for DatabaseKeyIndex -where - Db: ?Sized + Database, -{ - fn fmt( - &self, - f: &mut std::fmt::Formatter<'_>, - db: &Db, - include_all_fields: bool, - ) -> std::fmt::Result { - let i: DependencyIndex = (*self).into(); - DebugWithDb::fmt(&i, f, db, include_all_fields) - } -} - -impl From for DependencyIndex { - fn from(value: DatabaseKeyIndex) -> Self { - Self { - ingredient_index: value.ingredient_index, - key_index: Some(value.key_index), - } - } -} - -impl TryFrom for DatabaseKeyIndex { - type Error = (); - - fn try_from(value: DependencyIndex) -> Result { - let key_index = value.key_index.ok_or(())?; - Ok(Self { - ingredient_index: value.ingredient_index, - key_index, - }) - } -} diff --git a/third-party/vendor/salsa-2022/src/lib.rs b/third-party/vendor/salsa-2022/src/lib.rs deleted file mode 100644 index d3fe4ddd..00000000 --- a/third-party/vendor/salsa-2022/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -pub mod accumulator; -pub mod cancelled; -pub mod cycle; -pub mod database; -pub mod debug; -pub mod durability; -pub mod event; -pub mod function; -pub mod hash; -pub mod id; -pub mod ingredient; -pub mod ingredient_list; -pub mod input; -pub mod input_field; -pub mod interned; -pub mod jar; -pub mod key; -pub mod plumbing; -pub mod revision; -pub mod routes; -pub mod runtime; -pub mod salsa_struct; -pub mod setter; -pub mod storage; -#[doc(hidden)] -pub mod tracked_struct; - -pub use self::cancelled::Cancelled; -pub use self::cycle::Cycle; -pub use self::database::Database; -pub use self::database::ParallelDatabase; -pub use self::database::Snapshot; -pub use self::debug::DebugWith; -pub use self::debug::DebugWithDb; -pub use self::durability::Durability; -pub use self::event::Event; -pub use self::event::EventKind; -pub use self::id::AsId; -pub use self::id::Id; -pub use self::key::DatabaseKeyIndex; -pub use self::revision::Revision; -pub use self::routes::IngredientIndex; -pub use self::runtime::Runtime; -pub use self::storage::DbWithJar; -pub use self::storage::Storage; -pub use self::tracked_struct::TrackedStructData; -pub use self::tracked_struct::TrackedStructId; -pub use salsa_2022_macros::accumulator; -pub use salsa_2022_macros::db; -pub use salsa_2022_macros::input; -pub use salsa_2022_macros::interned; -pub use salsa_2022_macros::jar; -pub use salsa_2022_macros::tracked; diff --git a/third-party/vendor/salsa-2022/src/plumbing.rs b/third-party/vendor/salsa-2022/src/plumbing.rs deleted file mode 100644 index 65a06451..00000000 --- a/third-party/vendor/salsa-2022/src/plumbing.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::{alloc, ptr}; - -use crate::storage::HasJars; - -/// Initializes the `DB`'s jars in-place -/// -/// # Safety: -/// -/// `init` must fully initialize all of jars fields -pub unsafe fn create_jars_inplace(init: impl FnOnce(*mut DB::Jars)) -> Box { - let layout = alloc::Layout::new::(); - - if layout.size() == 0 { - // SAFETY: This is the recommended way of creating a Box - // to a ZST in the std docs - unsafe { Box::from_raw(ptr::NonNull::dangling().as_ptr()) } - } else { - // SAFETY: We've checked that the size isn't 0 - let place = unsafe { alloc::alloc_zeroed(layout) }; - let place = place.cast::(); - - init(place); - - // SAFETY: Caller invariant requires that `init` must've - // initialized all of the fields - unsafe { Box::from_raw(place) } - } -} diff --git a/third-party/vendor/salsa-2022/src/revision.rs b/third-party/vendor/salsa-2022/src/revision.rs deleted file mode 100644 index a98a4585..00000000 --- a/third-party/vendor/salsa-2022/src/revision.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::num::NonZeroUsize; -use std::sync::atomic::{AtomicUsize, Ordering}; - -/// Value of the initial revision, as a u64. We don't use 0 -/// because we want to use a `NonZeroUsize`. -const START: usize = 1; - -/// A unique identifier for the current version of the database; each -/// time an input is changed, the revision number is incremented. -/// `Revision` is used internally to track which values may need to be -/// recomputed, but is not something you should have to interact with -/// directly as a user of salsa. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Revision { - generation: NonZeroUsize, -} - -impl Revision { - pub(crate) fn start() -> Self { - Self::from(START) - } - - pub(crate) fn from(g: usize) -> Self { - Self { - generation: NonZeroUsize::new(g).unwrap(), - } - } - - pub(crate) fn next(self) -> Revision { - Self::from(self.generation.get() + 1) - } - - fn as_usize(self) -> usize { - self.generation.get() - } -} - -impl std::fmt::Debug for Revision { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "R{}", self.generation) - } -} - -#[derive(Debug)] -pub(crate) struct AtomicRevision { - data: AtomicUsize, -} - -impl AtomicRevision { - pub(crate) fn start() -> Self { - Self { - data: AtomicUsize::new(START), - } - } - - pub(crate) fn load(&self) -> Revision { - Revision::from(self.data.load(Ordering::SeqCst)) - } - - pub(crate) fn store(&self, r: Revision) { - self.data.store(r.as_usize(), Ordering::SeqCst); - } -} diff --git a/third-party/vendor/salsa-2022/src/routes.rs b/third-party/vendor/salsa-2022/src/routes.rs deleted file mode 100644 index 1226bc0a..00000000 --- a/third-party/vendor/salsa-2022/src/routes.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::ingredient::IngredientRequiresReset; - -use super::{ingredient::Ingredient, storage::HasJars}; - -/// An ingredient index identifies a particular [`Ingredient`] in the database. -/// The database contains a number of jars, and each jar contains a number of ingredients. -/// Each ingredient is given a unique index as the database is being created. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct IngredientIndex(u32); - -impl IngredientIndex { - /// Create an ingredient index from a usize. - fn from(v: usize) -> Self { - assert!(v < (std::u32::MAX as usize)); - Self(v as u32) - } - - /// Convert the ingredient index back into a usize. - fn as_usize(self) -> usize { - self.0 as usize - } -} - -/// A "route" is a function that, given a `&DB::Jars`, returns an `&dyn Ingredient`. -/// Routes are constructed (in part) from closures generated by the salsa macros. -/// These closures look essentially like `|jar| &jar.some_field` -- i.e., if a jar is a struct, -/// the closure returns a reference to some particular field of the struct -/// (whichever field has the database for this ingredient). -/// -/// The key point here is: the struct definitions that are being referencd here come from -/// crates that consume this crate, and hence we cannot name them directly. -/// We have to navigate them through closures generated by that downstream crate. -#[allow(type_alias_bounds)] -#[allow(unused_parens)] -pub type DynRoute = dyn Fn(&DB::Jars) -> (&dyn Ingredient) + Send + Sync; - -/// Like a `DynRoute`, but for `&mut` references. -#[allow(type_alias_bounds)] -#[allow(unused_parens)] -pub type DynMutRoute = - dyn Fn(&mut DB::Jars) -> (&mut dyn Ingredient) + Send + Sync; - -/// The "routes" structure is used to navigate the database. -/// The database contains a number of jars, and each jar contains a number of ingredients. -/// When the database is created, it creates each jar in turn. -/// Each jar then creates its ingredients. -/// Each ingredient is registered with the database by invoking the [`Routes::push`] method. -/// This method assigns it a unique [`IngredientIndex`] and stores some callbacks indicating -/// how to find the ingredient later based only on the index. -pub struct Routes { - /// Vector indexed by ingredient index. Yields the `DynRoute`, - /// a function which can be applied to the `DB::Jars` to yield - /// the `dyn Ingredient. - #[allow(clippy::type_complexity)] - routes: Vec<(Box>, Box>)>, - - /// Indices of routes which need a 'reset' call. - needs_reset: Vec, -} - -impl Routes { - /// Construct an empty ingredients listing. - pub(super) fn new() -> Self { - Routes { - routes: vec![], - needs_reset: vec![], - } - } - - /// Adds a new ingredient into the ingredients table, returning - /// the `IngredientIndex` that can be used in a `DatabaseKeyIndex`. - /// This index can then be used to fetch the "route" so that we can - /// dispatch calls to `maybe_changed_after`. - /// - /// # Parameters - /// - /// * `requires_reset` -- if true, the [`Ingredient::reset_for_new_revision`] method will be called on this ingredient - /// at each new revision. See that method for more information. - /// * `route` -- a closure which, given a database, will identify the ingredient. - /// This closure will be invoked to dispatch calls to `maybe_changed_after`. - /// * `mut_route` -- a closure which identifies the ingredient in a mut - /// database. - pub fn push( - &mut self, - route: impl (Fn(&DB::Jars) -> &I) + Send + Sync + 'static, - mut_route: impl (Fn(&mut DB::Jars) -> &mut I) + Send + Sync + 'static, - ) -> IngredientIndex - where - I: Ingredient + IngredientRequiresReset + 'static, - { - let len = self.routes.len(); - self.routes.push(( - Box::new(move |jars| route(jars)), - Box::new(move |jars| mut_route(jars)), - )); - let index = IngredientIndex::from(len); - - if I::RESET_ON_NEW_REVISION { - self.needs_reset.push(index); - } - - index - } - - /// Given an ingredient index, return the "route" - /// (a function that, given a `&Jars`, returns the ingredient). - pub fn route(&self, index: IngredientIndex) -> &dyn Fn(&DB::Jars) -> &dyn Ingredient { - &self.routes[index.as_usize()].0 - } - - /// Given an ingredient index, return the "mut route" - /// (a function that, given an `&mut Jars`, returns the ingredient). - pub fn route_mut( - &self, - index: IngredientIndex, - ) -> &dyn Fn(&mut DB::Jars) -> &mut dyn Ingredient { - &self.routes[index.as_usize()].1 - } - - /// Returns the mut routes for ingredients that need to be reset at the start of each revision. - pub fn reset_routes( - &self, - ) -> impl Iterator &mut dyn Ingredient> + '_ { - self.needs_reset.iter().map(|&index| self.route_mut(index)) - } -} diff --git a/third-party/vendor/salsa-2022/src/runtime.rs b/third-party/vendor/salsa-2022/src/runtime.rs deleted file mode 100644 index ad2cc879..00000000 --- a/third-party/vendor/salsa-2022/src/runtime.rs +++ /dev/null @@ -1,444 +0,0 @@ -use std::{ - panic::panic_any, - sync::{atomic::Ordering, Arc}, -}; - -use crate::{ - cycle::CycleRecoveryStrategy, - debug::DebugWithDb, - durability::Durability, - key::{DatabaseKeyIndex, DependencyIndex}, - runtime::active_query::ActiveQuery, - Cancelled, Cycle, Database, Event, EventKind, Revision, -}; - -use self::{ - dependency_graph::DependencyGraph, - local_state::{ActiveQueryGuard, EdgeKind}, -}; - -use super::{tracked_struct::Disambiguator, IngredientIndex}; - -mod active_query; -mod dependency_graph; -pub mod local_state; -mod shared_state; - -pub struct Runtime { - /// Our unique runtime id. - id: RuntimeId, - - /// Local state that is specific to this runtime (thread). - local_state: local_state::LocalState, - - /// Shared state that is accessible via all runtimes. - shared_state: Arc, -} - -#[derive(Clone, Debug)] -pub(crate) enum WaitResult { - Completed, - Panicked, - Cycle(Cycle), -} - -/// A unique identifier for a particular runtime. Each time you create -/// a snapshot, a fresh `RuntimeId` is generated. Once a snapshot is -/// complete, its `RuntimeId` may potentially be re-used. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct RuntimeId { - counter: usize, -} - -#[derive(Clone, Debug)] -pub(crate) struct StampedValue { - pub(crate) value: V, - pub(crate) durability: Durability, - pub(crate) changed_at: Revision, -} - -impl StampedValue { - // FIXME: Use or remove this. - #[allow(dead_code)] - pub(crate) fn merge_revision_info(&mut self, other: &StampedValue) { - self.durability = self.durability.min(other.durability); - self.changed_at = self.changed_at.max(other.changed_at); - } -} - -impl Default for Runtime { - fn default() -> Self { - Runtime { - id: RuntimeId { counter: 0 }, - shared_state: Default::default(), - local_state: Default::default(), - } - } -} - -impl std::fmt::Debug for Runtime { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - fmt.debug_struct("Runtime") - .field("id", &self.id()) - .field("shared_state", &self.shared_state) - .finish() - } -} - -impl Runtime { - pub(crate) fn id(&self) -> RuntimeId { - self.id - } - - pub(crate) fn current_revision(&self) -> Revision { - self.shared_state.revisions[0].load() - } - - /// Returns the index of the active query along with its *current* durability/changed-at - /// information. As the query continues to execute, naturally, that information may change. - pub(crate) fn active_query(&self) -> Option<(DatabaseKeyIndex, StampedValue<()>)> { - self.local_state.active_query() - } - - pub(crate) fn empty_dependencies(&self) -> Arc<[(EdgeKind, DependencyIndex)]> { - self.shared_state.empty_dependencies.clone() - } - - pub fn snapshot(&self) -> Self { - if self.local_state.query_in_progress() { - panic!("it is not legal to `snapshot` during a query (see salsa-rs/salsa#80)"); - } - - let id = RuntimeId { - counter: self.shared_state.next_id.fetch_add(1, Ordering::SeqCst), - }; - - Runtime { - id, - shared_state: self.shared_state.clone(), - local_state: Default::default(), - } - } - - pub(crate) fn report_tracked_read( - &self, - key_index: DependencyIndex, - durability: Durability, - changed_at: Revision, - ) { - self.local_state - .report_tracked_read(key_index, durability, changed_at) - } - - /// Reports that the query depends on some state unknown to salsa. - /// - /// Queries which report untracked reads will be re-executed in the next - /// revision. - pub fn report_untracked_read(&self) { - self.local_state - .report_untracked_read(self.current_revision()); - } - - /// Reports that an input with durability `durability` changed. - /// This will update the 'last changed at' values for every durability - /// less than or equal to `durability` to the current revision. - pub(crate) fn report_tracked_write(&mut self, durability: Durability) { - let new_revision = self.current_revision(); - for rev in &self.shared_state.revisions[1..=durability.index()] { - rev.store(new_revision); - } - } - - /// Adds `key` to the list of output created by the current query - /// (if not already present). - pub(crate) fn add_output(&self, key: DependencyIndex) { - self.local_state.add_output(key); - } - - /// Check whether `entity` is contained the list of outputs written by the current query. - pub(super) fn is_output_of_active_query(&self, entity: DependencyIndex) -> bool { - self.local_state.is_output(entity) - } - - /// Called when the active queries creates an index from the - /// entity table with the index `entity_index`. Has the following effects: - /// - /// * Add a query read on `DatabaseKeyIndex::for_table(entity_index)` - /// * Identify a unique disambiguator for the hash within the current query, - /// adding the hash to the current query's disambiguator table. - /// * Return that hash + id of the current query. - pub(crate) fn disambiguate_entity( - &self, - entity_index: IngredientIndex, - reset_at: Revision, - data_hash: u64, - ) -> (DatabaseKeyIndex, Disambiguator) { - self.report_tracked_read( - DependencyIndex::for_table(entity_index), - Durability::MAX, - reset_at, - ); - self.local_state.disambiguate(data_hash) - } - - /// The revision in which values with durability `d` may have last - /// changed. For D0, this is just the current revision. But for - /// higher levels of durability, this value may lag behind the - /// current revision. If we encounter a value of durability Di, - /// then, we can check this function to get a "bound" on when the - /// value may have changed, which allows us to skip walking its - /// dependencies. - #[inline] - pub(crate) fn last_changed_revision(&self, d: Durability) -> Revision { - self.shared_state.revisions[d.index()].load() - } - - /// Starts unwinding the stack if the current revision is cancelled. - /// - /// This method can be called by query implementations that perform - /// potentially expensive computations, in order to speed up propagation of - /// cancellation. - /// - /// Cancellation will automatically be triggered by salsa on any query - /// invocation. - /// - /// This method should not be overridden by `Database` implementors. A - /// `salsa_event` is emitted when this method is called, so that should be - /// used instead. - pub(crate) fn unwind_if_revision_cancelled(&self, db: &DB) { - db.salsa_event(Event { - runtime_id: self.id(), - kind: EventKind::WillCheckCancellation, - }); - if self.shared_state.revision_canceled.load() { - db.salsa_event(Event { - runtime_id: self.id(), - kind: EventKind::WillCheckCancellation, - }); - self.unwind_cancelled(); - } - } - - #[cold] - pub(crate) fn unwind_cancelled(&self) { - self.report_untracked_read(); - Cancelled::PendingWrite.throw(); - } - - pub(crate) fn set_cancellation_flag(&self) { - self.shared_state.revision_canceled.store(true); - } - - /// Increments the "current revision" counter and clears - /// the cancellation flag. - /// - /// This should only be done by the storage when the state is "quiescent". - pub(crate) fn new_revision(&mut self) -> Revision { - let r_old = self.current_revision(); - let r_new = r_old.next(); - self.shared_state.revisions[0].store(r_new); - self.shared_state.revision_canceled.store(false); - r_new - } - - #[inline] - pub(crate) fn push_query(&self, database_key_index: DatabaseKeyIndex) -> ActiveQueryGuard<'_> { - self.local_state.push_query(database_key_index) - } - - /// Block until `other_id` completes executing `database_key`; - /// panic or unwind in the case of a cycle. - /// - /// `query_mutex_guard` is the guard for the current query's state; - /// it will be dropped after we have successfully registered the - /// dependency. - /// - /// # Propagating panics - /// - /// If the thread `other_id` panics, then our thread is considered - /// cancelled, so this function will panic with a `Cancelled` value. - /// - /// # Cycle handling - /// - /// If the thread `other_id` already depends on the current thread, - /// and hence there is a cycle in the query graph, then this function - /// will unwind instead of returning normally. The method of unwinding - /// depends on the [`Self::mutual_cycle_recovery_strategy`] - /// of the cycle participants: - /// - /// * [`CycleRecoveryStrategy::Panic`]: panic with the [`Cycle`] as the value. - /// * [`CycleRecoveryStrategy::Fallback`]: initiate unwinding with [`CycleParticipant::unwind`]. - pub(crate) fn block_on_or_unwind( - &self, - db: &dyn Database, - database_key: DatabaseKeyIndex, - other_id: RuntimeId, - query_mutex_guard: QueryMutexGuard, - ) { - let mut dg = self.shared_state.dependency_graph.lock(); - - if dg.depends_on(other_id, self.id()) { - self.unblock_cycle_and_maybe_throw(db, &mut dg, database_key, other_id); - - // If the above fn returns, then (via cycle recovery) it has unblocked the - // cycle, so we can continue. - assert!(!dg.depends_on(other_id, self.id())); - } - - db.salsa_event(Event { - runtime_id: self.id(), - kind: EventKind::WillBlockOn { - other_runtime_id: other_id, - database_key, - }, - }); - - let stack = self.local_state.take_query_stack(); - - let (stack, result) = DependencyGraph::block_on( - dg, - self.id(), - database_key, - other_id, - stack, - query_mutex_guard, - ); - - self.local_state.restore_query_stack(stack); - - match result { - WaitResult::Completed => (), - - // If the other thread panicked, then we consider this thread - // cancelled. The assumption is that the panic will be detected - // by the other thread and responded to appropriately. - WaitResult::Panicked => Cancelled::PropagatedPanic.throw(), - - WaitResult::Cycle(c) => c.throw(), - } - } - - /// Handles a cycle in the dependency graph that was detected when the - /// current thread tried to block on `database_key_index` which is being - /// executed by `to_id`. If this function returns, then `to_id` no longer - /// depends on the current thread, and so we should continue executing - /// as normal. Otherwise, the function will throw a `Cycle` which is expected - /// to be caught by some frame on our stack. This occurs either if there is - /// a frame on our stack with cycle recovery (possibly the top one!) or if there - /// is no cycle recovery at all. - fn unblock_cycle_and_maybe_throw( - &self, - db: &dyn Database, - dg: &mut DependencyGraph, - database_key_index: DatabaseKeyIndex, - to_id: RuntimeId, - ) { - log::debug!( - "unblock_cycle_and_maybe_throw(database_key={:?})", - database_key_index - ); - - let mut from_stack = self.local_state.take_query_stack(); - let from_id = self.id(); - - // Make a "dummy stack frame". As we iterate through the cycle, we will collect the - // inputs from each participant. Then, if we are participating in cycle recovery, we - // will propagate those results to all participants. - let mut cycle_query = ActiveQuery::new(database_key_index); - - // Identify the cycle participants: - let cycle = { - let mut v = vec![]; - dg.for_each_cycle_participant( - from_id, - &mut from_stack, - database_key_index, - to_id, - |aqs| { - aqs.iter_mut().for_each(|aq| { - cycle_query.add_from(aq); - v.push(aq.database_key_index); - }); - }, - ); - - // We want to give the participants in a deterministic order - // (at least for this execution, not necessarily across executions), - // no matter where it started on the stack. Find the minimum - // key and rotate it to the front. - let min = v.iter().min().unwrap(); - let index = v.iter().position(|p| p == min).unwrap(); - v.rotate_left(index); - - // No need to store extra memory. - v.shrink_to_fit(); - - Cycle::new(Arc::new(v)) - }; - log::debug!( - "cycle {:?}, cycle_query {:#?}", - cycle.debug(db), - cycle_query, - ); - - // We can remove the cycle participants from the list of dependencies; - // they are a strongly connected component (SCC) and we only care about - // dependencies to things outside the SCC that control whether it will - // form again. - cycle_query.remove_cycle_participants(&cycle); - - // Mark each cycle participant that has recovery set, along with - // any frames that come after them on the same thread. Those frames - // are going to be unwound so that fallback can occur. - dg.for_each_cycle_participant(from_id, &mut from_stack, database_key_index, to_id, |aqs| { - aqs.iter_mut() - .skip_while(|aq| { - match db.cycle_recovery_strategy(aq.database_key_index.ingredient_index) { - CycleRecoveryStrategy::Panic => true, - CycleRecoveryStrategy::Fallback => false, - } - }) - .for_each(|aq| { - log::debug!("marking {:?} for fallback", aq.database_key_index.debug(db)); - aq.take_inputs_from(&cycle_query); - assert!(aq.cycle.is_none()); - aq.cycle = Some(cycle.clone()); - }); - }); - - // Unblock every thread that has cycle recovery with a `WaitResult::Cycle`. - // They will throw the cycle, which will be caught by the frame that has - // cycle recovery so that it can execute that recovery. - let (me_recovered, others_recovered) = - dg.maybe_unblock_runtimes_in_cycle(from_id, &from_stack, database_key_index, to_id); - - self.local_state.restore_query_stack(from_stack); - - if me_recovered { - // If the current thread has recovery, we want to throw - // so that it can begin. - cycle.throw() - } else if others_recovered { - // If other threads have recovery but we didn't: return and we will block on them. - } else { - // if nobody has recover, then we panic - panic_any(cycle); - } - } - - /// Invoked when this runtime completed computing `database_key` with - /// the given result `wait_result` (`wait_result` should be `None` if - /// computing `database_key` panicked and could not complete). - /// This function unblocks any dependent queries and allows them - /// to continue executing. - pub(crate) fn unblock_queries_blocked_on( - &self, - database_key: DatabaseKeyIndex, - wait_result: WaitResult, - ) { - self.shared_state - .dependency_graph - .lock() - .unblock_runtimes_blocked_on(database_key, wait_result); - } -} diff --git a/third-party/vendor/salsa-2022/src/runtime/active_query.rs b/third-party/vendor/salsa-2022/src/runtime/active_query.rs deleted file mode 100644 index ebe33a48..00000000 --- a/third-party/vendor/salsa-2022/src/runtime/active_query.rs +++ /dev/null @@ -1,147 +0,0 @@ -use crate::{ - durability::Durability, - hash::{FxIndexMap, FxIndexSet}, - key::{DatabaseKeyIndex, DependencyIndex}, - tracked_struct::Disambiguator, - Cycle, Revision, Runtime, -}; - -use super::local_state::{EdgeKind, QueryEdges, QueryOrigin, QueryRevisions}; - -#[derive(Debug)] -pub(super) struct ActiveQuery { - /// What query is executing - pub(super) database_key_index: DatabaseKeyIndex, - - /// Minimum durability of inputs observed so far. - pub(super) durability: Durability, - - /// Maximum revision of all inputs observed. If we observe an - /// untracked read, this will be set to the most recent revision. - pub(super) changed_at: Revision, - - /// Inputs: Set of subqueries that were accessed thus far. - /// Outputs: Tracks values written by this query. Could be... - /// - /// * tracked structs created - /// * invocations of `specify` - /// * accumulators pushed to - pub(super) input_outputs: FxIndexSet<(EdgeKind, DependencyIndex)>, - - /// True if there was an untracked read. - pub(super) untracked_read: bool, - - /// Stores the entire cycle, if one is found and this query is part of it. - pub(super) cycle: Option, - - /// When new entities are created, their data is hashed, and the resulting - /// hash is added to this map. If it is not present, then the disambiguator is 0. - /// Otherwise it is 1 more than the current value (which is incremented). - pub(super) disambiguator_map: FxIndexMap, -} - -impl ActiveQuery { - pub(super) fn new(database_key_index: DatabaseKeyIndex) -> Self { - ActiveQuery { - database_key_index, - durability: Durability::MAX, - changed_at: Revision::start(), - input_outputs: FxIndexSet::default(), - untracked_read: false, - cycle: None, - disambiguator_map: Default::default(), - } - } - - pub(super) fn add_read( - &mut self, - input: DependencyIndex, - durability: Durability, - revision: Revision, - ) { - self.input_outputs.insert((EdgeKind::Input, input)); - self.durability = self.durability.min(durability); - self.changed_at = self.changed_at.max(revision); - } - - pub(super) fn add_untracked_read(&mut self, changed_at: Revision) { - self.untracked_read = true; - self.durability = Durability::LOW; - self.changed_at = changed_at; - } - - pub(super) fn add_synthetic_read(&mut self, durability: Durability, revision: Revision) { - self.untracked_read = true; - self.durability = self.durability.min(durability); - self.changed_at = self.changed_at.max(revision); - } - - /// Adds a key to our list of outputs. - pub(super) fn add_output(&mut self, key: DependencyIndex) { - self.input_outputs.insert((EdgeKind::Output, key)); - } - - /// True if the given key was output by this query. - pub(super) fn is_output(&self, key: DependencyIndex) -> bool { - self.input_outputs.contains(&(EdgeKind::Output, key)) - } - - pub(crate) fn revisions(&self, runtime: &Runtime) -> QueryRevisions { - let input_outputs = if self.input_outputs.is_empty() { - runtime.empty_dependencies() - } else { - self.input_outputs.iter().copied().collect() - }; - - let edges = QueryEdges::new(input_outputs); - - let origin = if self.untracked_read { - QueryOrigin::DerivedUntracked(edges) - } else { - QueryOrigin::Derived(edges) - }; - - QueryRevisions { - changed_at: self.changed_at, - origin, - durability: self.durability, - } - } - - /// Adds any dependencies from `other` into `self`. - /// Used during cycle recovery, see [`Runtime::create_cycle_error`]. - pub(super) fn add_from(&mut self, other: &ActiveQuery) { - self.changed_at = self.changed_at.max(other.changed_at); - self.durability = self.durability.min(other.durability); - self.untracked_read |= other.untracked_read; - self.input_outputs - .extend(other.input_outputs.iter().copied()); - } - - /// Removes the participants in `cycle` from my dependencies. - /// Used during cycle recovery, see [`Runtime::create_cycle_error`]. - pub(super) fn remove_cycle_participants(&mut self, cycle: &Cycle) { - for p in cycle.participant_keys() { - let p: DependencyIndex = p.into(); - self.input_outputs.remove(&(EdgeKind::Input, p)); - } - } - - /// Copy the changed-at, durability, and dependencies from `cycle_query`. - /// Used during cycle recovery, see [`Runtime::create_cycle_error`]. - pub(crate) fn take_inputs_from(&mut self, cycle_query: &ActiveQuery) { - self.changed_at = cycle_query.changed_at; - self.durability = cycle_query.durability; - self.input_outputs = cycle_query.input_outputs.clone(); - } - - pub(super) fn disambiguate(&mut self, hash: u64) -> Disambiguator { - let disambiguator = self - .disambiguator_map - .entry(hash) - .or_insert(Disambiguator(0)); - let result = *disambiguator; - disambiguator.0 += 1; - result - } -} diff --git a/third-party/vendor/salsa-2022/src/runtime/dependency_graph.rs b/third-party/vendor/salsa-2022/src/runtime/dependency_graph.rs deleted file mode 100644 index 85a0460f..00000000 --- a/third-party/vendor/salsa-2022/src/runtime/dependency_graph.rs +++ /dev/null @@ -1,277 +0,0 @@ -use std::sync::Arc; - -use crate::key::DatabaseKeyIndex; -use parking_lot::{Condvar, MutexGuard}; -use rustc_hash::FxHashMap; -use smallvec::SmallVec; - -use super::{active_query::ActiveQuery, RuntimeId, WaitResult}; - -type QueryStack = Vec; - -#[derive(Debug, Default)] -pub(super) struct DependencyGraph { - /// A `(K -> V)` pair in this map indicates that the the runtime - /// `K` is blocked on some query executing in the runtime `V`. - /// This encodes a graph that must be acyclic (or else deadlock - /// will result). - edges: FxHashMap, - - /// Encodes the `RuntimeId` that are blocked waiting for the result - /// of a given query. - query_dependents: FxHashMap>, - - /// When a key K completes which had dependent queries Qs blocked on it, - /// it stores its `WaitResult` here. As they wake up, each query Q in Qs will - /// come here to fetch their results. - wait_results: FxHashMap, -} - -#[derive(Debug)] -struct Edge { - blocked_on_id: RuntimeId, - blocked_on_key: DatabaseKeyIndex, - stack: QueryStack, - - /// Signalled whenever a query with dependents completes. - /// Allows those dependents to check if they are ready to unblock. - condvar: Arc, -} - -impl DependencyGraph { - /// True if `from_id` depends on `to_id`. - /// - /// (i.e., there is a path from `from_id` to `to_id` in the graph.) - pub(super) fn depends_on(&mut self, from_id: RuntimeId, to_id: RuntimeId) -> bool { - let mut p = from_id; - while let Some(q) = self.edges.get(&p).map(|edge| edge.blocked_on_id) { - if q == to_id { - return true; - } - - p = q; - } - p == to_id - } - - /// Invokes `closure` with a `&mut ActiveQuery` for each query that participates in the cycle. - /// The cycle runs as follows: - /// - /// 1. The runtime `from_id`, which has the stack `from_stack`, would like to invoke `database_key`... - /// 2. ...but `database_key` is already being executed by `to_id`... - /// 3. ...and `to_id` is transitively dependent on something which is present on `from_stack`. - pub(super) fn for_each_cycle_participant( - &mut self, - from_id: RuntimeId, - from_stack: &mut QueryStack, - database_key: DatabaseKeyIndex, - to_id: RuntimeId, - mut closure: impl FnMut(&mut [ActiveQuery]), - ) { - debug_assert!(self.depends_on(to_id, from_id)); - - // To understand this algorithm, consider this [drawing](https://is.gd/TGLI9v): - // - // database_key = QB2 - // from_id = A - // to_id = B - // from_stack = [QA1, QA2, QA3] - // - // self.edges[B] = { C, QC2, [QB1..QB3] } - // self.edges[C] = { A, QA2, [QC1..QC3] } - // - // The cyclic - // edge we have - // failed to add. - // : - // A : B C - // : - // QA1 v QB1 QC1 - // ┌► QA2 ┌──► QB2 ┌─► QC2 - // │ QA3 ───┘ QB3 ──┘ QC3 ───┐ - // │ │ - // └───────────────────────────────┘ - // - // Final output: [QB2, QB3, QC2, QC3, QA2, QA3] - - let mut id = to_id; - let mut key = database_key; - while id != from_id { - // Looking at the diagram above, the idea is to - // take the edge from `to_id` starting at `key` - // (inclusive) and down to the end. We can then - // load up the next thread (i.e., we start at B/QB2, - // and then load up the dependency on C/QC2). - let edge = self.edges.get_mut(&id).unwrap(); - let prefix = edge - .stack - .iter_mut() - .take_while(|p| p.database_key_index != key) - .count(); - closure(&mut edge.stack[prefix..]); - id = edge.blocked_on_id; - key = edge.blocked_on_key; - } - - // Finally, we copy in the results from `from_stack`. - let prefix = from_stack - .iter_mut() - .take_while(|p| p.database_key_index != key) - .count(); - closure(&mut from_stack[prefix..]); - } - - /// Unblock each blocked runtime (excluding the current one) if some - /// query executing in that runtime is participating in cycle fallback. - /// - /// Returns a boolean (Current, Others) where: - /// * Current is true if the current runtime has cycle participants - /// with fallback; - /// * Others is true if other runtimes were unblocked. - pub(super) fn maybe_unblock_runtimes_in_cycle( - &mut self, - from_id: RuntimeId, - from_stack: &QueryStack, - database_key: DatabaseKeyIndex, - to_id: RuntimeId, - ) -> (bool, bool) { - // See diagram in `for_each_cycle_participant`. - let mut id = to_id; - let mut key = database_key; - let mut others_unblocked = false; - while id != from_id { - let edge = self.edges.get(&id).unwrap(); - let prefix = edge - .stack - .iter() - .take_while(|p| p.database_key_index != key) - .count(); - let next_id = edge.blocked_on_id; - let next_key = edge.blocked_on_key; - - if let Some(cycle) = edge.stack[prefix..] - .iter() - .rev() - .find_map(|aq| aq.cycle.clone()) - { - // Remove `id` from the list of runtimes blocked on `next_key`: - self.query_dependents - .get_mut(&next_key) - .unwrap() - .retain(|r| *r != id); - - // Unblock runtime so that it can resume execution once lock is released: - self.unblock_runtime(id, WaitResult::Cycle(cycle)); - - others_unblocked = true; - } - - id = next_id; - key = next_key; - } - - let prefix = from_stack - .iter() - .take_while(|p| p.database_key_index != key) - .count(); - let this_unblocked = from_stack[prefix..].iter().any(|aq| aq.cycle.is_some()); - - (this_unblocked, others_unblocked) - } - - /// Modifies the graph so that `from_id` is blocked - /// on `database_key`, which is being computed by - /// `to_id`. - /// - /// For this to be reasonable, the lock on the - /// results table for `database_key` must be held. - /// This ensures that computing `database_key` doesn't - /// complete before `block_on` executes. - /// - /// Preconditions: - /// * No path from `to_id` to `from_id` - /// (i.e., `me.depends_on(to_id, from_id)` is false) - /// * `held_mutex` is a read lock (or stronger) on `database_key` - pub(super) fn block_on( - mut me: MutexGuard<'_, Self>, - from_id: RuntimeId, - database_key: DatabaseKeyIndex, - to_id: RuntimeId, - from_stack: QueryStack, - query_mutex_guard: QueryMutexGuard, - ) -> (QueryStack, WaitResult) { - let condvar = me.add_edge(from_id, database_key, to_id, from_stack); - - // Release the mutex that prevents `database_key` - // from completing, now that the edge has been added. - drop(query_mutex_guard); - - loop { - if let Some(stack_and_result) = me.wait_results.remove(&from_id) { - debug_assert!(!me.edges.contains_key(&from_id)); - return stack_and_result; - } - condvar.wait(&mut me); - } - } - - /// Helper for `block_on`: performs actual graph modification - /// to add a dependency edge from `from_id` to `to_id`, which is - /// computing `database_key`. - fn add_edge( - &mut self, - from_id: RuntimeId, - database_key: DatabaseKeyIndex, - to_id: RuntimeId, - from_stack: QueryStack, - ) -> Arc { - assert_ne!(from_id, to_id); - debug_assert!(!self.edges.contains_key(&from_id)); - debug_assert!(!self.depends_on(to_id, from_id)); - - let condvar = Arc::new(Condvar::new()); - self.edges.insert( - from_id, - Edge { - blocked_on_id: to_id, - blocked_on_key: database_key, - stack: from_stack, - condvar: condvar.clone(), - }, - ); - self.query_dependents - .entry(database_key) - .or_default() - .push(from_id); - condvar - } - - /// Invoked when runtime `to_id` completes executing - /// `database_key`. - pub(super) fn unblock_runtimes_blocked_on( - &mut self, - database_key: DatabaseKeyIndex, - wait_result: WaitResult, - ) { - let dependents = self - .query_dependents - .remove(&database_key) - .unwrap_or_default(); - - for from_id in dependents { - self.unblock_runtime(from_id, wait_result.clone()); - } - } - - /// Unblock the runtime with the given id with the given wait-result. - /// This will cause it resume execution (though it will have to grab - /// the lock on this data structure first, to recover the wait result). - fn unblock_runtime(&mut self, id: RuntimeId, wait_result: WaitResult) { - let edge = self.edges.remove(&id).expect("not blocked"); - self.wait_results.insert(id, (edge.stack, wait_result)); - - // Now that we have inserted the `wait_results`, - // notify the thread. - edge.condvar.notify_one(); - } -} diff --git a/third-party/vendor/salsa-2022/src/runtime/local_state.rs b/third-party/vendor/salsa-2022/src/runtime/local_state.rs deleted file mode 100644 index 57724d3c..00000000 --- a/third-party/vendor/salsa-2022/src/runtime/local_state.rs +++ /dev/null @@ -1,364 +0,0 @@ -use log::debug; - -use crate::durability::Durability; -use crate::key::DatabaseKeyIndex; -use crate::key::DependencyIndex; -use crate::runtime::Revision; -use crate::tracked_struct::Disambiguator; -use crate::Cycle; -use crate::Runtime; -use std::cell::RefCell; -use std::sync::Arc; - -use super::active_query::ActiveQuery; -use super::StampedValue; - -/// State that is specific to a single execution thread. -/// -/// Internally, this type uses ref-cells. -/// -/// **Note also that all mutations to the database handle (and hence -/// to the local-state) must be undone during unwinding.** -pub(super) struct LocalState { - /// Vector of active queries. - /// - /// This is normally `Some`, but it is set to `None` - /// while the query is blocked waiting for a result. - /// - /// Unwinding note: pushes onto this vector must be popped -- even - /// during unwinding. - query_stack: RefCell>>, -} - -/// Summarizes "all the inputs that a query used" -#[derive(Debug, Clone)] -pub(crate) struct QueryRevisions { - /// The most revision in which some input changed. - pub(crate) changed_at: Revision, - - /// Minimum durability of the inputs to this query. - pub(crate) durability: Durability, - - /// How was this query computed? - pub(crate) origin: QueryOrigin, -} - -impl QueryRevisions { - pub(crate) fn stamped_value(&self, value: V) -> StampedValue { - StampedValue { - value, - durability: self.durability, - changed_at: self.changed_at, - } - } -} - -/// Tracks the way that a memoized value for a query was created. -#[derive(Debug, Clone)] -pub enum QueryOrigin { - /// The value was assigned as the output of another query (e.g., using `specify`). - /// The `DatabaseKeyIndex` is the identity of the assigning query. - Assigned(DatabaseKeyIndex), - - /// This value was set as a base input to the computation. - BaseInput, - - /// The value was derived by executing a function - /// and we were able to track ALL of that function's inputs. - /// Those inputs are described in [`QueryEdges`]. - Derived(QueryEdges), - - /// The value was derived by executing a function - /// but that function also reported that it read untracked inputs. - /// The [`QueryEdges`] argument contains a listing of all the inputs we saw - /// (but we know there were more). - DerivedUntracked(QueryEdges), -} - -impl QueryOrigin { - /// Indices for queries *written* by this query (or `vec![]` if its value was assigned). - pub(crate) fn outputs(&self) -> impl Iterator + '_ { - let opt_edges = match self { - QueryOrigin::Derived(edges) | QueryOrigin::DerivedUntracked(edges) => Some(edges), - QueryOrigin::Assigned(_) | QueryOrigin::BaseInput => None, - }; - opt_edges.into_iter().flat_map(|edges| edges.outputs()) - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum EdgeKind { - Input, - Output, -} - -/// The edges between a memoized value and other queries in the dependency graph. -/// These edges include both dependency edges -/// e.g., when creating the memoized value for Q0 executed another function Q1) -/// and output edges -/// (e.g., when Q0 specified the value for another query Q2). -#[derive(Debug, Clone)] -pub struct QueryEdges { - /// The list of outgoing edges from this node. - /// This list combines *both* inputs and outputs. - /// - /// Note that we always track input dependencies even when there are untracked reads. - /// Untracked reads mean that we can't verify values, so we don't use the list of inputs for that, - /// but we still use it for finding the transitive inputs to an accumulator. - /// - /// You can access the input/output list via the methods [`inputs`] and [`outputs`] respectively. - /// - /// Important: - /// - /// * The inputs must be in **execution order** for the red-green algorithm to work. - pub input_outputs: Arc<[(EdgeKind, DependencyIndex)]>, -} - -impl QueryEdges { - /// Returns the (tracked) inputs that were executed in computing this memoized value. - /// - /// These will always be in execution order. - pub(crate) fn inputs(&self) -> impl Iterator + '_ { - self.input_outputs - .iter() - .filter(|(edge_kind, _)| *edge_kind == EdgeKind::Input) - .map(|(_, dependency_index)| *dependency_index) - } - - /// Returns the (tracked) outputs that were executed in computing this memoized value. - /// - /// These will always be in execution order. - pub(crate) fn outputs(&self) -> impl Iterator + '_ { - self.input_outputs - .iter() - .filter(|(edge_kind, _)| *edge_kind == EdgeKind::Output) - .map(|(_, dependency_index)| *dependency_index) - } - - /// Creates a new `QueryEdges`; the values given for each field must meet struct invariants. - pub(crate) fn new(input_outputs: Arc<[(EdgeKind, DependencyIndex)]>) -> Self { - Self { input_outputs } - } -} - -impl Default for LocalState { - fn default() -> Self { - LocalState { - query_stack: RefCell::new(Some(Vec::new())), - } - } -} - -impl LocalState { - #[inline] - pub(super) fn push_query(&self, database_key_index: DatabaseKeyIndex) -> ActiveQueryGuard<'_> { - let mut query_stack = self.query_stack.borrow_mut(); - let query_stack = query_stack.as_mut().expect("local stack taken"); - query_stack.push(ActiveQuery::new(database_key_index)); - ActiveQueryGuard { - local_state: self, - database_key_index, - push_len: query_stack.len(), - } - } - - fn with_query_stack(&self, c: impl FnOnce(&mut Vec) -> R) -> R { - c(self - .query_stack - .borrow_mut() - .as_mut() - .expect("query stack taken")) - } - - pub(super) fn query_in_progress(&self) -> bool { - self.with_query_stack(|stack| !stack.is_empty()) - } - - /// Returns the index of the active query along with its *current* durability/changed-at - /// information. As the query continues to execute, naturally, that information may change. - pub(super) fn active_query(&self) -> Option<(DatabaseKeyIndex, StampedValue<()>)> { - self.with_query_stack(|stack| { - stack.last().map(|active_query| { - ( - active_query.database_key_index, - StampedValue { - value: (), - durability: active_query.durability, - changed_at: active_query.changed_at, - }, - ) - }) - }) - } - - pub(super) fn add_output(&self, entity: DependencyIndex) { - self.with_query_stack(|stack| { - if let Some(top_query) = stack.last_mut() { - top_query.add_output(entity) - } - }) - } - - pub(super) fn is_output(&self, entity: DependencyIndex) -> bool { - self.with_query_stack(|stack| { - if let Some(top_query) = stack.last_mut() { - top_query.is_output(entity) - } else { - false - } - }) - } - - pub(super) fn report_tracked_read( - &self, - input: DependencyIndex, - durability: Durability, - changed_at: Revision, - ) { - debug!( - "report_query_read_and_unwind_if_cycle_resulted(input={:?}, durability={:?}, changed_at={:?})", - input, durability, changed_at - ); - self.with_query_stack(|stack| { - if let Some(top_query) = stack.last_mut() { - top_query.add_read(input, durability, changed_at); - - // We are a cycle participant: - // - // C0 --> ... --> Ci --> Ci+1 -> ... -> Cn --> C0 - // ^ ^ - // : | - // This edge -----+ | - // | - // | - // N0 - // - // In this case, the value we have just read from `Ci+1` - // is actually the cycle fallback value and not especially - // interesting. We unwind now with `CycleParticipant` to avoid - // executing the rest of our query function. This unwinding - // will be caught and our own fallback value will be used. - // - // Note that `Ci+1` may` have *other* callers who are not - // participants in the cycle (e.g., N0 in the graph above). - // They will not have the `cycle` marker set in their - // stack frames, so they will just read the fallback value - // from `Ci+1` and continue on their merry way. - if let Some(cycle) = &top_query.cycle { - cycle.clone().throw() - } - } - }) - } - - pub(super) fn report_untracked_read(&self, current_revision: Revision) { - self.with_query_stack(|stack| { - if let Some(top_query) = stack.last_mut() { - top_query.add_untracked_read(current_revision); - } - }) - } - - /// Update the top query on the stack to act as though it read a value - /// of durability `durability` which changed in `revision`. - // FIXME: Use or remove this. - #[allow(dead_code)] - pub(super) fn report_synthetic_read(&self, durability: Durability, revision: Revision) { - self.with_query_stack(|stack| { - if let Some(top_query) = stack.last_mut() { - top_query.add_synthetic_read(durability, revision); - } - }) - } - - /// Takes the query stack and returns it. This is used when - /// the current thread is blocking. The stack must be restored - /// with [`Self::restore_query_stack`] when the thread unblocks. - pub(super) fn take_query_stack(&self) -> Vec { - assert!( - self.query_stack.borrow().is_some(), - "query stack already taken" - ); - self.query_stack.take().unwrap() - } - - /// Restores a query stack taken with [`Self::take_query_stack`] once - /// the thread unblocks. - pub(super) fn restore_query_stack(&self, stack: Vec) { - assert!(self.query_stack.borrow().is_none(), "query stack not taken"); - self.query_stack.replace(Some(stack)); - } - - #[track_caller] - pub(crate) fn disambiguate(&self, data_hash: u64) -> (DatabaseKeyIndex, Disambiguator) { - assert!( - self.query_in_progress(), - "cannot create a tracked struct disambiguator outside of a tracked function" - ); - self.with_query_stack(|stack| { - let top_query = stack.last_mut().unwrap(); - let disambiguator = top_query.disambiguate(data_hash); - (top_query.database_key_index, disambiguator) - }) - } -} - -impl std::panic::RefUnwindSafe for LocalState {} - -/// When a query is pushed onto the `active_query` stack, this guard -/// is returned to represent its slot. The guard can be used to pop -/// the query from the stack -- in the case of unwinding, the guard's -/// destructor will also remove the query. -pub(crate) struct ActiveQueryGuard<'me> { - local_state: &'me LocalState, - push_len: usize, - pub(crate) database_key_index: DatabaseKeyIndex, -} - -impl ActiveQueryGuard<'_> { - fn pop_helper(&self) -> ActiveQuery { - self.local_state.with_query_stack(|stack| { - // Sanity check: pushes and pops should be balanced. - assert_eq!(stack.len(), self.push_len); - debug_assert_eq!( - stack.last().unwrap().database_key_index, - self.database_key_index - ); - stack.pop().unwrap() - }) - } - - /// Invoked when the query has successfully completed execution. - pub(super) fn complete(self) -> ActiveQuery { - let query = self.pop_helper(); - std::mem::forget(self); - query - } - - /// Pops an active query from the stack. Returns the [`QueryRevisions`] - /// which summarizes the other queries that were accessed during this - /// query's execution. - #[inline] - pub(crate) fn pop(self, runtime: &Runtime) -> QueryRevisions { - // Extract accumulated inputs. - let popped_query = self.complete(); - - // If this frame were a cycle participant, it would have unwound. - assert!(popped_query.cycle.is_none()); - - popped_query.revisions(runtime) - } - - /// If the active query is registered as a cycle participant, remove and - /// return that cycle. - pub(crate) fn take_cycle(&self) -> Option { - self.local_state - .with_query_stack(|stack| stack.last_mut()?.cycle.take()) - } -} - -impl Drop for ActiveQueryGuard<'_> { - fn drop(&mut self) { - self.pop_helper(); - } -} diff --git a/third-party/vendor/salsa-2022/src/runtime/shared_state.rs b/third-party/vendor/salsa-2022/src/runtime/shared_state.rs deleted file mode 100644 index 9a05b52e..00000000 --- a/third-party/vendor/salsa-2022/src/runtime/shared_state.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::sync::{atomic::AtomicUsize, Arc}; - -use crossbeam::atomic::AtomicCell; -use parking_lot::Mutex; - -use crate::{durability::Durability, key::DependencyIndex, revision::AtomicRevision}; - -use super::{dependency_graph::DependencyGraph, local_state::EdgeKind}; - -/// State that will be common to all threads (when we support multiple threads) -#[derive(Debug)] -pub(super) struct SharedState { - /// Stores the next id to use for a snapshotted runtime (starts at 1). - pub(super) next_id: AtomicUsize, - - /// Vector we can clone - pub(super) empty_dependencies: Arc<[(EdgeKind, DependencyIndex)]>, - - /// Set to true when the current revision has been canceled. - /// This is done when we an input is being changed. The flag - /// is set back to false once the input has been changed. - pub(super) revision_canceled: AtomicCell, - - /// Stores the "last change" revision for values of each duration. - /// This vector is always of length at least 1 (for Durability 0) - /// but its total length depends on the number of durations. The - /// element at index 0 is special as it represents the "current - /// revision". In general, we have the invariant that revisions - /// in here are *declining* -- that is, `revisions[i] >= - /// revisions[i + 1]`, for all `i`. This is because when you - /// modify a value with durability D, that implies that values - /// with durability less than D may have changed too. - pub(super) revisions: Vec, - - /// The dependency graph tracks which runtimes are blocked on one - /// another, waiting for queries to terminate. - pub(super) dependency_graph: Mutex, -} - -impl Default for SharedState { - fn default() -> Self { - Self::with_durabilities(Durability::LEN) - } -} - -impl SharedState { - fn with_durabilities(durabilities: usize) -> Self { - SharedState { - next_id: AtomicUsize::new(1), - empty_dependencies: None.into_iter().collect(), - revision_canceled: Default::default(), - revisions: (0..durabilities).map(|_| AtomicRevision::start()).collect(), - dependency_graph: Default::default(), - } - } -} diff --git a/third-party/vendor/salsa-2022/src/salsa_struct.rs b/third-party/vendor/salsa-2022/src/salsa_struct.rs deleted file mode 100644 index 913d85d6..00000000 --- a/third-party/vendor/salsa-2022/src/salsa_struct.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::{Database, IngredientIndex}; - -pub trait SalsaStructInDb { - fn register_dependent_fn(db: &DB, index: IngredientIndex); -} - -/// A ZST that implements [`SalsaStructInDb`] -/// -/// It is used for implementing "constant" tracked function -/// (ones that only take a database as an argument). -pub struct Singleton; - -impl SalsaStructInDb for Singleton { - fn register_dependent_fn(_db: &DB, _index: IngredientIndex) {} -} diff --git a/third-party/vendor/salsa-2022/src/setter.rs b/third-party/vendor/salsa-2022/src/setter.rs deleted file mode 100644 index f23289a2..00000000 --- a/third-party/vendor/salsa-2022/src/setter.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::input_field::InputFieldIngredient; -use crate::{AsId, Durability, Runtime}; -use std::hash::Hash; - -#[must_use] -pub struct Setter<'setter, K, F> { - runtime: &'setter mut Runtime, - key: K, - ingredient: &'setter mut InputFieldIngredient, - durability: Durability, -} - -impl<'setter, K, F> Setter<'setter, K, F> -where - K: Eq + Hash + AsId, -{ - pub fn new( - runtime: &'setter mut Runtime, - key: K, - ingredient: &'setter mut InputFieldIngredient, - ) -> Self { - Setter { - runtime, - key, - ingredient, - durability: Durability::LOW, - } - } - - pub fn with_durability(self, durability: Durability) -> Self { - Setter { durability, ..self } - } - - pub fn to(self, value: F) -> F { - self.ingredient - .store_mut(self.runtime, self.key, value, self.durability) - .unwrap() - } -} diff --git a/third-party/vendor/salsa-2022/src/storage.rs b/third-party/vendor/salsa-2022/src/storage.rs deleted file mode 100644 index 49b0a50a..00000000 --- a/third-party/vendor/salsa-2022/src/storage.rs +++ /dev/null @@ -1,264 +0,0 @@ -use std::{fmt, sync::Arc}; - -use parking_lot::Condvar; - -use crate::cycle::CycleRecoveryStrategy; -use crate::ingredient::Ingredient; -use crate::jar::Jar; -use crate::key::DependencyIndex; -use crate::runtime::local_state::QueryOrigin; -use crate::runtime::Runtime; -use crate::{Database, DatabaseKeyIndex, Id, IngredientIndex}; - -use super::routes::Routes; -use super::{ParallelDatabase, Revision}; - -/// The "storage" struct stores all the data for the jars. -/// It is shared between the main database and any active snapshots. -pub struct Storage { - /// Data shared across all databases. This contains the ingredients needed by each jar. - /// See the ["jars and ingredients" chapter](https://salsa-rs.github.io/salsa/plumbing/jars_and_ingredients.html) - /// for more detailed description. - shared: Shared, - - /// The "ingredients" structure stores the information about how to find each ingredient in the database. - /// It allows us to take the [`IngredientIndex`] assigned to a particular ingredient - /// and get back a [`dyn Ingredient`][`Ingredient`] for the struct that stores its data. - /// - /// This is kept separate from `shared` so that we can clone it and retain `&`-access even when we have `&mut` access to `shared`. - routes: Arc>, - - /// The runtime for this particular salsa database handle. - /// Each handle gets its own runtime, but the runtimes have shared state between them. - runtime: Runtime, -} - -/// Data shared between all threads. -/// This is where the actual data for tracked functions, structs, inputs, etc lives, -/// along with some coordination variables between treads. -struct Shared { - /// Contains the data for each jar in the database. - /// Each jar stores its own structs in there that ultimately contain ingredients - /// (types that implement the [`Ingredient`] trait, like [`crate::function::FunctionIngredient`]). - /// - /// Even though these jars are stored in an `Arc`, we sometimes get mutable access to them - /// by using `Arc::get_mut`. This is only possible when all parallel snapshots have been dropped. - jars: Option>, - - /// Conditional variable that is used to coordinate cancellation. - /// When the main thread writes to the database, it blocks until each of the snapshots can be cancelled. - cvar: Arc, -} - -// ANCHOR: default -impl Default for Storage -where - DB: HasJars, -{ - fn default() -> Self { - let mut routes = Routes::new(); - let jars = DB::create_jars(&mut routes); - Self { - shared: Shared { - jars: Some(Arc::from(jars)), - cvar: Arc::new(Default::default()), - }, - routes: Arc::new(routes), - runtime: Runtime::default(), - } - } -} -// ANCHOR_END: default - -impl Storage -where - DB: HasJars, -{ - pub fn snapshot(&self) -> Storage - where - DB: ParallelDatabase, - { - Self { - shared: self.shared.clone(), - routes: self.routes.clone(), - runtime: self.runtime.snapshot(), - } - } - - pub fn jars(&self) -> (&DB::Jars, &Runtime) { - (self.shared.jars.as_ref().unwrap(), &self.runtime) - } - - pub fn runtime(&self) -> &Runtime { - &self.runtime - } - - pub fn runtime_mut(&mut self) -> &mut Runtime { - self.jars_mut().1 - } - - // ANCHOR: jars_mut - /// Gets mutable access to the jars. This will trigger a new revision - /// and it will also cancel any ongoing work in the current revision. - /// Any actual writes that occur to data in a jar should use - /// [`Runtime::report_tracked_write`]. - pub fn jars_mut(&mut self) -> (&mut DB::Jars, &mut Runtime) { - // Wait for all snapshots to be dropped. - self.cancel_other_workers(); - - // Increment revision counter. - self.runtime.new_revision(); - - // Acquire `&mut` access to `self.shared` -- this is only possible because - // the snapshots have all been dropped, so we hold the only handle to the `Arc`. - let jars = Arc::get_mut(self.shared.jars.as_mut().unwrap()).unwrap(); - - // Inform other ingredients that a new revision has begun. - // This gives them a chance to free resources that were being held until the next revision. - let routes = self.routes.clone(); - for route in routes.reset_routes() { - route(jars).reset_for_new_revision(); - } - - // Return mut ref to jars + runtime. - (jars, &mut self.runtime) - } - // ANCHOR_END: jars_mut - - // ANCHOR: cancel_other_workers - /// Sets cancellation flag and blocks until all other workers with access - /// to this storage have completed. - /// - /// This could deadlock if there is a single worker with two handles to the - /// same database! - fn cancel_other_workers(&mut self) { - loop { - self.runtime.set_cancellation_flag(); - - // If we have unique access to the jars, we are done. - if Arc::get_mut(self.shared.jars.as_mut().unwrap()).is_some() { - return; - } - - // Otherwise, wait until some other storage entities have dropped. - // We create a mutex here because the cvar api requires it, but we - // don't really need one as the data being protected is actually - // the jars above. - // - // The cvar `self.shared.cvar` is notified by the `Drop` impl. - let mutex = parking_lot::Mutex::new(()); - let mut guard = mutex.lock(); - self.shared.cvar.wait(&mut guard); - } - } - // ANCHOR_END: cancel_other_workers - - pub fn ingredient(&self, ingredient_index: IngredientIndex) -> &dyn Ingredient { - let route = self.routes.route(ingredient_index); - route(self.shared.jars.as_ref().unwrap()) - } -} - -impl Clone for Shared -where - DB: HasJars, -{ - fn clone(&self) -> Self { - Self { - jars: self.jars.clone(), - cvar: self.cvar.clone(), - } - } -} - -impl Drop for Storage -where - DB: HasJars, -{ - fn drop(&mut self) { - // Drop the Arc reference before the cvar is notified, - // since other threads are sleeping, waiting for it to reach 1. - drop(self.shared.jars.take()); - self.shared.cvar.notify_all(); - } -} - -pub trait HasJars: HasJarsDyn + Sized { - type Jars; - - fn jars(&self) -> (&Self::Jars, &Runtime); - - /// Gets mutable access to the jars. This will trigger a new revision - /// and it will also cancel any ongoing work in the current revision. - fn jars_mut(&mut self) -> (&mut Self::Jars, &mut Runtime); - - fn create_jars(routes: &mut Routes) -> Box; -} - -pub trait DbWithJar: HasJar + Database { - fn as_jar_db<'db>(&'db self) -> &>::DynDb - where - J: Jar<'db>; -} - -pub trait JarFromJars: HasJars { - fn jar_from_jars(jars: &Self::Jars) -> &J; - - fn jar_from_jars_mut(jars: &mut Self::Jars) -> &mut J; -} - -pub trait HasJar { - fn jar(&self) -> (&J, &Runtime); - - fn jar_mut(&mut self) -> (&mut J, &mut Runtime); -} - -// ANCHOR: HasJarsDyn -/// Dyn friendly subset of HasJars -pub trait HasJarsDyn { - fn runtime(&self) -> &Runtime; - - fn runtime_mut(&mut self) -> &mut Runtime; - - fn maybe_changed_after(&self, input: DependencyIndex, revision: Revision) -> bool; - - fn cycle_recovery_strategy(&self, input: IngredientIndex) -> CycleRecoveryStrategy; - - fn origin(&self, input: DatabaseKeyIndex) -> Option; - - fn mark_validated_output(&self, executor: DatabaseKeyIndex, output: DependencyIndex); - - /// Invoked when `executor` used to output `stale_output` but no longer does. - /// This method routes that into a call to the [`remove_stale_output`](`crate::ingredient::Ingredient::remove_stale_output`) - /// method on the ingredient for `stale_output`. - fn remove_stale_output(&self, executor: DatabaseKeyIndex, stale_output: DependencyIndex); - - /// Informs `ingredient` that the salsa struct with id `id` has been deleted. - /// This means that `id` will not be used in this revision and hence - /// any memoized values keyed by that struct can be discarded. - /// - /// In order to receive this callback, `ingredient` must have registered itself - /// as a dependent function using - /// [`SalsaStructInDb::register_dependent_fn`](`crate::salsa_struct::SalsaStructInDb::register_dependent_fn`). - fn salsa_struct_deleted(&self, ingredient: IngredientIndex, id: Id); - - fn fmt_index(&self, index: DependencyIndex, fmt: &mut fmt::Formatter<'_>) -> fmt::Result; -} -// ANCHOR_END: HasJarsDyn - -pub trait HasIngredientsFor -where - I: IngredientsFor, -{ - fn ingredient(&self) -> &I::Ingredients; - fn ingredient_mut(&mut self) -> &mut I::Ingredients; -} - -pub trait IngredientsFor { - type Jar; - type Ingredients; - - fn create_ingredients(routes: &mut Routes) -> Self::Ingredients - where - DB: DbWithJar + JarFromJars; -} diff --git a/third-party/vendor/salsa-2022/src/tracked_struct.rs b/third-party/vendor/salsa-2022/src/tracked_struct.rs deleted file mode 100644 index ac0b39c2..00000000 --- a/third-party/vendor/salsa-2022/src/tracked_struct.rs +++ /dev/null @@ -1,198 +0,0 @@ -use std::fmt; - -use crate::{ - cycle::CycleRecoveryStrategy, - ingredient::{fmt_index, Ingredient, IngredientRequiresReset}, - ingredient_list::IngredientList, - interned::{InternedData, InternedId, InternedIngredient}, - key::{DatabaseKeyIndex, DependencyIndex}, - runtime::{local_state::QueryOrigin, Runtime}, - salsa_struct::SalsaStructInDb, - Database, Event, IngredientIndex, Revision, -}; - -pub trait TrackedStructId: InternedId {} -impl TrackedStructId for T {} - -pub trait TrackedStructData: InternedData {} -impl TrackedStructData for T {} - -pub trait TrackedStructInDb: SalsaStructInDb { - /// Converts the identifier for this tracked struct into a `DatabaseKeyIndex`. - fn database_key_index(self, db: &DB) -> DatabaseKeyIndex; -} - -/// Created for each tracked struct. -/// This ingredient only stores the "id" fields. -/// It is a kind of "dressed up" interner; -/// the active query + values of id fields are hashed to create the tracked struct id. -/// The value fields are stored in [`crate::function::FunctionIngredient`] instances keyed by the tracked struct id. -/// Unlike normal interners, tracked struct indices can be deleted and reused aggressively: -/// when a tracked function re-executes, -/// any tracked structs that it created before but did not create this time can be deleted. -pub struct TrackedStructIngredient -where - Id: TrackedStructId, - Data: TrackedStructData, -{ - interned: InternedIngredient>, - - /// A list of each tracked function `f` whose key is this - /// tracked struct. - /// - /// Whenever an instance `i` of this struct is deleted, - /// each of these functions will be notified - /// so they can remove any data tied to that instance. - dependent_fns: IngredientList, - - debug_name: &'static str, -} - -#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] -struct TrackedStructKey { - query_key: Option, - disambiguator: Disambiguator, - data: Data, -} - -#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] -pub struct Disambiguator(pub u32); - -impl TrackedStructIngredient -where - Id: TrackedStructId, - Data: TrackedStructData, -{ - pub fn new(index: IngredientIndex, debug_name: &'static str) -> Self { - Self { - interned: InternedIngredient::new(index, debug_name), - dependent_fns: IngredientList::new(), - debug_name, - } - } - - pub fn database_key_index(&self, id: Id) -> DatabaseKeyIndex { - DatabaseKeyIndex { - ingredient_index: self.interned.ingredient_index(), - key_index: id.as_id(), - } - } - - pub fn new_struct(&self, runtime: &Runtime, data: Data) -> Id { - let data_hash = crate::hash::hash(&data); - let (query_key, disambiguator) = runtime.disambiguate_entity( - self.interned.ingredient_index(), - self.interned.reset_at(), - data_hash, - ); - let entity_key = TrackedStructKey { - query_key: Some(query_key), - disambiguator, - data, - }; - let result = self.interned.intern(runtime, entity_key); - runtime.add_output(self.database_key_index(result).into()); - result - } - - pub fn tracked_struct_data<'db>(&'db self, runtime: &'db Runtime, id: Id) -> &'db Data { - &self.interned.data(runtime, id).data - } - - /// Deletes the given entities. This is used after a query `Q` executes and we can compare - /// the entities `E_now` that it produced in this revision vs the entities - /// `E_prev` it produced in the last revision. Any missing entities `E_prev - E_new` can be - /// deleted. - /// - /// # Warning - /// - /// Using this method on an entity id that MAY be used in the current revision will lead to - /// unspecified results (but not UB). See [`InternedIngredient::delete_index`] for more - /// discussion and important considerations. - pub(crate) fn delete_entity(&self, db: &dyn crate::Database, id: Id) { - db.salsa_event(Event { - runtime_id: db.runtime().id(), - kind: crate::EventKind::DidDiscard { - key: self.database_key_index(id), - }, - }); - - self.interned.delete_index(id); - for dependent_fn in self.dependent_fns.iter() { - db.salsa_struct_deleted(dependent_fn, id.as_id()); - } - } - - /// Adds a dependent function (one keyed by this tracked struct) to our list. - /// When instances of this struct are deleted, these dependent functions - /// will be notified. - pub fn register_dependent_fn(&self, index: IngredientIndex) { - self.dependent_fns.push(index); - } -} - -impl Ingredient for TrackedStructIngredient -where - Id: TrackedStructId, - Data: TrackedStructData, - DB: crate::Database, -{ - fn ingredient_index(&self) -> IngredientIndex { - self.interned.ingredient_index() - } - - fn maybe_changed_after(&self, db: &DB, input: DependencyIndex, revision: Revision) -> bool { - self.interned.maybe_changed_after(db, input, revision) - } - - fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy { - <_ as Ingredient>::cycle_recovery_strategy(&self.interned) - } - - fn origin(&self, _key_index: crate::Id) -> Option { - None - } - - fn mark_validated_output( - &self, - _db: &DB, - _executor: DatabaseKeyIndex, - _output_key: Option, - ) { - // FIXME - } - - fn remove_stale_output( - &self, - db: &DB, - _executor: DatabaseKeyIndex, - stale_output_key: Option, - ) { - // This method is called when, in prior revisions, - // `executor` creates a tracked struct `salsa_output_key`, - // but it did not in the current revision. - // In that case, we can delete `stale_output_key` and any data associated with it. - let stale_output_key: Id = Id::from_id(stale_output_key.unwrap()); - self.delete_entity(db.as_salsa_database(), stale_output_key); - } - - fn reset_for_new_revision(&mut self) { - self.interned.clear_deleted_indices(); - } - - fn salsa_struct_deleted(&self, _db: &DB, _id: crate::Id) { - panic!("unexpected call: interned ingredients do not register for salsa struct deletion events"); - } - - fn fmt_index(&self, index: Option, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_index(self.debug_name, index, fmt) - } -} - -impl IngredientRequiresReset for TrackedStructIngredient -where - Id: TrackedStructId, - Data: TrackedStructData, -{ - const RESET_ON_NEW_REVISION: bool = true; -}