build(rust): vendor rnix parser crate #57
52
Cargo.lock
generated
52
Cargo.lock
generated
@@ -107,6 +107,25 @@ version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||
|
||||
[[package]]
|
||||
name = "countme"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
|
||||
|
||||
[[package]]
|
||||
name = "direct-cargo-bazel-deps"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"rnix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -159,6 +178,33 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rnix"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c163bd17372eecdf10d351c34584b7de7c1a33be4e92a32f3fb3f5a7fe3f579b"
|
||||
dependencies = [
|
||||
"rowan",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rowan"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21"
|
||||
dependencies = [
|
||||
"countme",
|
||||
"hashbrown",
|
||||
"rustc-hash",
|
||||
"text-size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.229"
|
||||
@@ -219,6 +265,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "text-size"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
|
||||
7
third_party/BUILD
vendored
7
third_party/BUILD
vendored
@@ -1,4 +1,4 @@
|
||||
load("@rules_rust//crate_universe:defs.bzl", "crates_vendor")
|
||||
load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_vendor")
|
||||
|
||||
sh_binary(
|
||||
name = "bazel_for_cargo_bazel",
|
||||
@@ -10,6 +10,11 @@ crates_vendor(
|
||||
bazel = ":bazel_for_cargo_bazel",
|
||||
cargo_lockfile = "//:Cargo.lock",
|
||||
manifests = ["//:Cargo.toml"],
|
||||
packages = {
|
||||
"rnix": crate.spec(
|
||||
version = "=0.14.0",
|
||||
),
|
||||
},
|
||||
mode = "local",
|
||||
tags = ["manual"],
|
||||
vendor_path = "crates",
|
||||
|
||||
12
third_party/crates/BUILD.bazel
vendored
12
third_party/crates/BUILD.bazel
vendored
@@ -43,6 +43,18 @@ alias(
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "rnix-0.14.0",
|
||||
actual = "//third_party/crates/rnix-0.14.0:rnix",
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "rnix",
|
||||
actual = "//third_party/crates/rnix-0.14.0:rnix",
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "serde-1.0.229",
|
||||
actual = "//third_party/crates/serde-1.0.229:serde",
|
||||
|
||||
1
third_party/crates/countme-3.0.1/.cargo-checksum.json
vendored
Normal file
1
third_party/crates/countme-3.0.1/.cargo-checksum.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"c515c26023d43f1a2e58e72f727db7d9fa7262b6f8e08701c7841d2b0296a734",".vscode/settings.json":"2c3e2e5cbc3e4a0955637ed821f4105311669b187302034284200ad8bd387c38","Cargo.lock":"4101e28468b7a3c7a051247ff0d55ea1f2ba58e303857a7a4d3bbaef5caf31cc","Cargo.toml":"5ba3effabbc65115689252c397fb98adb04ac0174819612ecc4e754cea3acf1b","Cargo.toml.orig":"bb43c057350c53f12d2264c1bcbed48c4d181e34ea7de3a21060c97c0f7346e3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"8a8a5d00072b2f1c99a47b50e45cd2604485d1ce1b242eb7dd2895d4c8ca8625","examples/bench.rs":"a081e78268bdfd452840aa23d607bdfac0f57197ca6af35a5832e888fa59ddd2","examples/bench_single_thread.rs":"3e39d60ccb10cbd2905eaa154592af7024c690432f62f09b8211f9d601b39ab0","examples/print_at_exit.rs":"86ace893845110a7035a6aaab71c43640729f374a4be8224e9c559c6fe52f457","src/imp.rs":"dee6f26cd36f8c4062371349f7ff6091aff236edf3e4cccf3d898386dcf0f5bd","src/lib.rs":"c993efcdef9eed3c149f19d2429c59849381c7f61b264741c4ca1696de918974"},"package":"7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"}
|
||||
6
third_party/crates/countme-3.0.1/.cargo_vcs_info.json
vendored
Normal file
6
third_party/crates/countme-3.0.1/.cargo_vcs_info.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "9e037c4293fb8ef6c1c632094349734955f06d89"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
3
third_party/crates/countme-3.0.1/.vscode/settings.json
vendored
Normal file
3
third_party/crates/countme-3.0.1/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"rust-analyzer.cargo.features": ["enable", "print_at_exit"]
|
||||
}
|
||||
110
third_party/crates/countme-3.0.1/BUILD.bazel
vendored
Normal file
110
third_party/crates/countme-3.0.1/BUILD.bazel
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
###############################################################################
|
||||
# @generated
|
||||
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
|
||||
# regenerate this file, run the following:
|
||||
#
|
||||
# bazel run @@//third_party:vendor_crates
|
||||
###############################################################################
|
||||
|
||||
load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars")
|
||||
load("@rules_rust//rust:defs.bzl", "rust_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cargo_toml_env_vars(
|
||||
name = "cargo_toml_env_vars",
|
||||
src = "Cargo.toml",
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "countme",
|
||||
srcs = glob(
|
||||
include = ["**/*.rs"],
|
||||
allow_empty = False,
|
||||
),
|
||||
compile_data = glob(
|
||||
include = ["**"],
|
||||
allow_empty = True,
|
||||
exclude = [
|
||||
"**/* *",
|
||||
".tmp_git_root/**/*",
|
||||
"BUILD",
|
||||
"BUILD.bazel",
|
||||
"WORKSPACE",
|
||||
"WORKSPACE.bazel",
|
||||
],
|
||||
),
|
||||
crate_root = "src/lib.rs",
|
||||
edition = "2018",
|
||||
rustc_env_files = [
|
||||
":cargo_toml_env_vars",
|
||||
],
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-bazel",
|
||||
"crate-name=countme",
|
||||
"manual",
|
||||
"noclippy",
|
||||
"norustfmt",
|
||||
],
|
||||
target_compatible_with = select({
|
||||
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios-macabi": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
|
||||
"@rules_rust//rust/platform:aarch64-linux-android": [],
|
||||
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-fuchsia": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-none": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-uefi": [],
|
||||
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
|
||||
"@rules_rust//rust/platform:arm-unknown-linux-musleabi": [],
|
||||
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
|
||||
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
|
||||
"@rules_rust//rust/platform:i686-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:i686-linux-android": [],
|
||||
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
|
||||
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:mips-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-netbsd": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-openbsd": [],
|
||||
"@rules_rust//rust/platform:thumbv6m-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv7em-none-eabihf": [],
|
||||
"@rules_rust//rust/platform:thumbv7m-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [],
|
||||
"@rules_rust//rust/platform:wasm32-unknown-emscripten": [],
|
||||
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip1": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip1-threads": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip2": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-ios": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-ios-macabi": [],
|
||||
"@rules_rust//rust/platform:x86_64-linux-android": [],
|
||||
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-fuchsia": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-none": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-uefi": [],
|
||||
"//conditions:default": ["@platforms//:incompatible"],
|
||||
}),
|
||||
version = "3.0.1",
|
||||
)
|
||||
168
third_party/crates/countme-3.0.1/Cargo.lock
generated
vendored
Normal file
168
third_party/crates/countme-3.0.1/Cargo.lock
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "countme"
|
||||
version = "3.0.1"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"once_cell",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0834a35a3fce649144119e18da2a4d8ed12ef3862f47183fd46f625d072d96c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
|
||||
48
third_party/crates/countme-3.0.1/Cargo.toml
vendored
Normal file
48
third_party/crates/countme-3.0.1/Cargo.toml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# 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 = "countme"
|
||||
version = "3.0.1"
|
||||
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
|
||||
exclude = [".github/", "bors.toml", "rustfmt.toml"]
|
||||
description = "Counts the number of live instances of types"
|
||||
categories = ["development-tools::profiling"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/matklad/countme"
|
||||
|
||||
[[example]]
|
||||
name = "print_at_exit"
|
||||
required-features = ["print_at_exit"]
|
||||
|
||||
[[example]]
|
||||
name = "bench"
|
||||
required-features = ["enable"]
|
||||
|
||||
[[example]]
|
||||
name = "bench_single_thread"
|
||||
required-features = ["enable"]
|
||||
[dependencies.dashmap]
|
||||
version = "5.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.once_cell]
|
||||
version = "1.5"
|
||||
optional = true
|
||||
|
||||
[dependencies.rustc-hash]
|
||||
version = "1.1"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
enable = ["dashmap", "once_cell", "rustc-hash"]
|
||||
print_at_exit = ["enable"]
|
||||
35
third_party/crates/countme-3.0.1/Cargo.toml.orig
generated
vendored
Normal file
35
third_party/crates/countme-3.0.1/Cargo.toml.orig
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
[package]
|
||||
name = "countme"
|
||||
description = "Counts the number of live instances of types"
|
||||
version = "3.0.1"
|
||||
categories = ["development-tools::profiling"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/matklad/countme"
|
||||
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
exclude = [".github/", "bors.toml", "rustfmt.toml"]
|
||||
|
||||
[workspace]
|
||||
members = ["xtask"]
|
||||
|
||||
[[example]]
|
||||
name = "print_at_exit"
|
||||
required-features = ["print_at_exit"]
|
||||
|
||||
[[example]]
|
||||
name = "bench"
|
||||
required-features = ["enable"]
|
||||
|
||||
[[example]]
|
||||
name = "bench_single_thread"
|
||||
required-features = ["enable"]
|
||||
|
||||
[dependencies]
|
||||
dashmap = { version = "5.0", optional = true }
|
||||
once_cell = { version = "1.5", optional = true }
|
||||
rustc-hash = { version = "1.1", optional = true }
|
||||
|
||||
[features]
|
||||
enable = [ "dashmap", "once_cell", "rustc-hash" ]
|
||||
print_at_exit = ["enable"]
|
||||
201
third_party/crates/countme-3.0.1/LICENSE-APACHE
vendored
Normal file
201
third_party/crates/countme-3.0.1/LICENSE-APACHE
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
23
third_party/crates/countme-3.0.1/LICENSE-MIT
vendored
Normal file
23
third_party/crates/countme-3.0.1/LICENSE-MIT
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
21
third_party/crates/countme-3.0.1/README.md
vendored
Normal file
21
third_party/crates/countme-3.0.1/README.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
A library to quickly get the live/total/max counts of allocated instances.
|
||||
|
||||
```rust
|
||||
#[derive(Default)]
|
||||
struct Widget {
|
||||
_c: countme::Count<Self>,
|
||||
...
|
||||
}
|
||||
|
||||
let w1 = Widget::default();
|
||||
let w2 = Widget::default();
|
||||
let w3 = Widget::default();
|
||||
drop(w1);
|
||||
|
||||
let counts = countme::get::<Widget>();
|
||||
assert_eq!(counts.live, 2);
|
||||
assert_eq!(counts.max_live, 3);
|
||||
assert_eq!(counts.total, 3);
|
||||
|
||||
eprintln!("{}", countme::get_all());
|
||||
```
|
||||
69
third_party/crates/countme-3.0.1/examples/bench.rs
vendored
Normal file
69
third_party/crates/countme-3.0.1/examples/bench.rs
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
use std::thread;
|
||||
|
||||
use countme::{get, Count};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Foo {
|
||||
_c: Count<Self>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Bar {
|
||||
_c: Count<Self>,
|
||||
_x: i32,
|
||||
}
|
||||
|
||||
mod deeply {
|
||||
pub(crate) mod nested {
|
||||
pub(crate) mod module {
|
||||
use countme::Count;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Quux {
|
||||
_c: Count<Self>,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
countme::enable(true);
|
||||
let t = std::time::Instant::now();
|
||||
let n = 5;
|
||||
let m = 1_000_000;
|
||||
|
||||
let mut threads = Vec::new();
|
||||
for _ in 0..n {
|
||||
threads.push(thread::spawn(move || {
|
||||
for _ in 0..m {
|
||||
Foo::default();
|
||||
}
|
||||
}));
|
||||
threads.push(thread::spawn(move || {
|
||||
let mut xs = Vec::with_capacity(m);
|
||||
for _ in 0..m {
|
||||
xs.push(Bar::default())
|
||||
}
|
||||
}));
|
||||
threads.push(thread::spawn(move || {
|
||||
for _ in 0..m {
|
||||
deeply::nested::module::Quux::default();
|
||||
}
|
||||
}));
|
||||
}
|
||||
for t in threads {
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
||||
let foo = get::<Foo>();
|
||||
assert_eq!(foo.total, m * n);
|
||||
assert!(foo.max_live >= 1);
|
||||
assert_eq!(foo.live, 0);
|
||||
|
||||
let bar = get::<Bar>();
|
||||
assert_eq!(bar.total, m * n);
|
||||
assert!(bar.max_live >= m);
|
||||
assert_eq!(bar.live, 0);
|
||||
|
||||
println!("{:?}", t.elapsed());
|
||||
}
|
||||
77
third_party/crates/countme-3.0.1/examples/bench_single_thread.rs
vendored
Normal file
77
third_party/crates/countme-3.0.1/examples/bench_single_thread.rs
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
use countme::{get, Count};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Foo {
|
||||
_c: Count<Self>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Bar {
|
||||
_c: Count<Self>,
|
||||
_x: i32,
|
||||
}
|
||||
|
||||
mod deeply {
|
||||
pub(crate) mod nested {
|
||||
pub(crate) mod module {
|
||||
use countme::Count;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Quux {
|
||||
_c: Count<Self>,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
countme::enable(true);
|
||||
let t = std::time::Instant::now();
|
||||
let n = 6;
|
||||
let m = 2_000_000;
|
||||
|
||||
for _ in 0..n {
|
||||
for _ in 0..m {
|
||||
Foo::default();
|
||||
}
|
||||
|
||||
let mut xs = Vec::with_capacity(m);
|
||||
for _ in 0..m {
|
||||
xs.push(Bar::default())
|
||||
}
|
||||
|
||||
for _ in 0..m {
|
||||
deeply::nested::module::Quux::default();
|
||||
}
|
||||
|
||||
let fs = [
|
||||
|| drop(Foo::default()),
|
||||
|| drop(Bar::default()),
|
||||
|| drop(deeply::nested::module::Quux::default()),
|
||||
|| {
|
||||
#[derive(Default)]
|
||||
struct Local(Count<Self>);
|
||||
|
||||
Local::default();
|
||||
},
|
||||
];
|
||||
for i in 0..m {
|
||||
fs[i % 4]();
|
||||
}
|
||||
}
|
||||
|
||||
let foo = get::<Foo>();
|
||||
assert_eq!(foo.total, m * n + (m * n / 4));
|
||||
assert_eq!(foo.max_live, 1);
|
||||
assert_eq!(foo.live, 0);
|
||||
|
||||
let bar = get::<Bar>();
|
||||
assert_eq!(bar.total, m * n + (m * n / 4));
|
||||
|
||||
// FIXME: why +1? This seems like a bug
|
||||
// overreporting by 1 is not significant, but anyway
|
||||
assert_eq!(bar.max_live, m + 1);
|
||||
assert_eq!(bar.live, 0);
|
||||
|
||||
println!("{:?}", t.elapsed());
|
||||
}
|
||||
11
third_party/crates/countme-3.0.1/examples/print_at_exit.rs
vendored
Normal file
11
third_party/crates/countme-3.0.1/examples/print_at_exit.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#[derive(Default)]
|
||||
struct Widget {
|
||||
_t: countme::Count<Self>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let w1 = Widget::default();
|
||||
let _w2 = Widget::default();
|
||||
drop(w1);
|
||||
let _w3 = Widget::default();
|
||||
}
|
||||
175
third_party/crates/countme-3.0.1/src/imp.rs
vendored
Normal file
175
third_party/crates/countme-3.0.1/src/imp.rs
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
use std::{
|
||||
any::{type_name, TypeId},
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
hash::BuildHasherDefault,
|
||||
os::raw::c_int,
|
||||
sync::atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use dashmap::DashMap;
|
||||
use once_cell::sync::OnceCell;
|
||||
use rustc_hash::FxHasher;
|
||||
|
||||
use crate::{AllCounts, Counts};
|
||||
|
||||
static ENABLE: AtomicBool = AtomicBool::new(cfg!(feature = "print_at_exit"));
|
||||
|
||||
type GlobalStore = DashMap<TypeId, Arc<Store>, BuildHasherDefault<FxHasher>>;
|
||||
|
||||
#[inline]
|
||||
fn global_store() -> &'static GlobalStore {
|
||||
static MAP: OnceCell<GlobalStore> = OnceCell::new();
|
||||
MAP.get_or_init(|| {
|
||||
if cfg!(feature = "print_at_exit") {
|
||||
extern "C" {
|
||||
fn atexit(f: extern "C" fn()) -> c_int;
|
||||
}
|
||||
extern "C" fn print_at_exit() {
|
||||
eprint!("{}", get_all());
|
||||
}
|
||||
unsafe {
|
||||
atexit(print_at_exit);
|
||||
}
|
||||
}
|
||||
|
||||
GlobalStore::default()
|
||||
})
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static LOCAL: RefCell<HashMap<TypeId, Arc<Store>, BuildHasherDefault<FxHasher>>> = RefCell::default();
|
||||
}
|
||||
|
||||
pub(crate) fn enable(yes: bool) {
|
||||
ENABLE.store(yes, Relaxed);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn enabled() -> bool {
|
||||
ENABLE.load(Relaxed)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn dec<T: 'static>() {
|
||||
if enabled() {
|
||||
do_dec(TypeId::of::<T>())
|
||||
}
|
||||
}
|
||||
#[inline(never)]
|
||||
fn do_dec(key: TypeId) {
|
||||
LOCAL.with(|local| {
|
||||
// Fast path: we have needed store in thread local map
|
||||
if let Some(store) = local.borrow().get(&key) {
|
||||
store.dec();
|
||||
return;
|
||||
}
|
||||
|
||||
let global = global_store();
|
||||
|
||||
// Slightly slower: we don't have needed store in our thread local map,
|
||||
// but some other thread has already initialized the needed store in the global map
|
||||
if let Some(store) = global.get(&key) {
|
||||
let store = store.value();
|
||||
local.borrow_mut().insert(key, Arc::clone(store));
|
||||
store.inc();
|
||||
return;
|
||||
}
|
||||
|
||||
// We only decrement counter after incremenrting it, so this line is unreachable
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn inc<T: 'static>() {
|
||||
if enabled() {
|
||||
do_inc(TypeId::of::<T>(), type_name::<T>())
|
||||
}
|
||||
}
|
||||
#[inline(never)]
|
||||
fn do_inc(key: TypeId, name: &'static str) {
|
||||
LOCAL.with(|local| {
|
||||
// Fast path: we have needed store in thread local map
|
||||
if let Some(store) = local.borrow().get(&key) {
|
||||
store.inc();
|
||||
return;
|
||||
}
|
||||
|
||||
let global = global_store();
|
||||
|
||||
let copy = match global.get(&key) {
|
||||
// Slightly slower path: we don't have needed store in our thread local map,
|
||||
// but some other thread has already initialized the needed store in the global map
|
||||
Some(store) => {
|
||||
let store = store.value();
|
||||
store.inc();
|
||||
Arc::clone(store)
|
||||
}
|
||||
// Slow path: we are the first to initialize both global and local maps
|
||||
None => {
|
||||
let store = global
|
||||
.entry(key)
|
||||
.or_insert_with(|| Arc::new(Store { name, ..Store::default() }))
|
||||
.downgrade();
|
||||
let store = store.value();
|
||||
|
||||
store.inc();
|
||||
Arc::clone(store)
|
||||
}
|
||||
};
|
||||
|
||||
local.borrow_mut().insert(key, copy);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn get<T: 'static>() -> Counts {
|
||||
do_get(TypeId::of::<T>())
|
||||
}
|
||||
fn do_get(key: TypeId) -> Counts {
|
||||
global_store().entry(key).or_default().value().read()
|
||||
}
|
||||
|
||||
pub(crate) fn get_all() -> AllCounts {
|
||||
let mut entries = global_store()
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
let store = entry.value();
|
||||
(store.type_name(), store.read())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
entries.sort_by_key(|(name, _counts)| *name);
|
||||
AllCounts { entries }
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Store {
|
||||
total: AtomicUsize,
|
||||
max_live: AtomicUsize,
|
||||
live: AtomicUsize,
|
||||
name: &'static str,
|
||||
}
|
||||
|
||||
impl Store {
|
||||
fn inc(&self) {
|
||||
self.total.fetch_add(1, Relaxed);
|
||||
let live = self.live.fetch_add(1, Relaxed) + 1;
|
||||
self.max_live.fetch_max(live, Relaxed);
|
||||
}
|
||||
|
||||
fn dec(&self) {
|
||||
self.live.fetch_sub(1, Relaxed);
|
||||
}
|
||||
|
||||
fn read(&self) -> Counts {
|
||||
Counts {
|
||||
total: self.total.load(Relaxed),
|
||||
max_live: self.max_live.load(Relaxed),
|
||||
live: self.live.load(Relaxed),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_name(&self) -> &'static str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
193
third_party/crates/countme-3.0.1/src/lib.rs
vendored
Normal file
193
third_party/crates/countme-3.0.1/src/lib.rs
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
//! A library to quickly get the live/total/max counts of allocated instances.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! # if cfg!(not(feature = "enable")) { return; }
|
||||
//!
|
||||
//! #[derive(Default)]
|
||||
//! struct Widget {
|
||||
//! _c: countme::Count<Self>,
|
||||
//! }
|
||||
//!
|
||||
//! countme::enable(true);
|
||||
//!
|
||||
//! let w1 = Widget::default();
|
||||
//! let w2 = Widget::default();
|
||||
//! let w3 = Widget::default();
|
||||
//! drop(w1);
|
||||
//!
|
||||
//! let counts = countme::get::<Widget>();
|
||||
//! assert_eq!(counts.live, 2);
|
||||
//! assert_eq!(counts.max_live, 3);
|
||||
//! assert_eq!(counts.total, 3);
|
||||
//!
|
||||
//! eprintln!("{}", countme::get_all());
|
||||
//! ```
|
||||
//!
|
||||
//! # Configuration
|
||||
//!
|
||||
//! By default, the implementation compiles to no-ops. Therefore it is possible
|
||||
//! to include `Count` fields into library types.
|
||||
//!
|
||||
//! The `enable` cargo feature ungates the counting code. The feature can be
|
||||
//! enabled anywhere in the crate graph.
|
||||
//!
|
||||
//! At run-time, the counters are controlled with [`enable`] function. Counting
|
||||
//! is enabled by default if `print_at_exit` feature is enabled. Otherwise
|
||||
//! counting is disabled by default. Call `enable(true)` early in `main` to enable:
|
||||
//!
|
||||
//! ```rust
|
||||
//! fn main() {
|
||||
//! countme::enable(std::env::var("COUNTME").is_ok());
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The code is optimized for the case where counting is not enabled at runtime
|
||||
//! (counting is a relaxed load and a branch to a function call).
|
||||
//!
|
||||
//! The `print_at_exit` Cargo feature uses `atexit` call to print final counts
|
||||
//! before the program exits (it also enables counting at runtime). Use it only
|
||||
//! when you can't modify the main to print counts -- `atexit` is not guaranteed
|
||||
//! to work with rust's runtime.
|
||||
#[cfg(feature = "enable")]
|
||||
mod imp;
|
||||
|
||||
use std::{fmt, marker::PhantomData};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
#[non_exhaustive]
|
||||
pub struct Counts {
|
||||
/// The total number of tokens created.
|
||||
pub total: usize,
|
||||
/// The historical maximum of the `live` count.
|
||||
pub max_live: usize,
|
||||
/// The number of tokens which were created, but are not destroyed yet.
|
||||
pub live: usize,
|
||||
}
|
||||
|
||||
/// Store this inside your struct as `_c: countme::Count<Self>`.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Count<T: 'static> {
|
||||
ghost: PhantomData<fn(T)>,
|
||||
}
|
||||
|
||||
impl<T: 'static> Default for Count<T> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Clone for Count<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Count<T> {
|
||||
/// Create new `Count`, incrementing the corresponding count.
|
||||
#[inline]
|
||||
pub fn new() -> Count<T> {
|
||||
#[cfg(feature = "enable")]
|
||||
imp::inc::<T>();
|
||||
Count { ghost: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Drop for Count<T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
#[cfg(feature = "enable")]
|
||||
imp::dec::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable or disable counting at runtime.
|
||||
///
|
||||
/// Counting is enabled by default if `print_at_exit` feature is enabled.
|
||||
/// Otherwise counting is disabled by default.
|
||||
///
|
||||
/// If neither `enable` nor `print_at_exit` features are enabled, then this function is noop.
|
||||
pub fn enable(_yes: bool) {
|
||||
#[cfg(feature = "enable")]
|
||||
imp::enable(_yes);
|
||||
}
|
||||
|
||||
/// Returns the counts for the `T` type.
|
||||
#[inline]
|
||||
pub fn get<T: 'static>() -> Counts {
|
||||
#[cfg(feature = "enable")]
|
||||
{
|
||||
return imp::get::<T>();
|
||||
}
|
||||
#[cfg(not(feature = "enable"))]
|
||||
{
|
||||
return Counts::default();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a collection of counts for all types.
|
||||
pub fn get_all() -> AllCounts {
|
||||
#[cfg(feature = "enable")]
|
||||
{
|
||||
return imp::get_all();
|
||||
}
|
||||
#[cfg(not(feature = "enable"))]
|
||||
{
|
||||
return AllCounts::default();
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection of counts for all types.
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct AllCounts {
|
||||
entries: Vec<(&'static str, Counts)>,
|
||||
}
|
||||
|
||||
impl fmt::Display for AllCounts {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn sep(mut n: usize) -> String {
|
||||
let mut groups = Vec::new();
|
||||
while n >= 1000 {
|
||||
groups.push(format!("{:03}", n % 1000));
|
||||
n /= 1000;
|
||||
}
|
||||
groups.push(n.to_string());
|
||||
groups.reverse();
|
||||
groups.join("_")
|
||||
}
|
||||
|
||||
if self.entries.is_empty() {
|
||||
return if cfg!(feature = "enable") {
|
||||
writeln!(f, "all counts are zero")
|
||||
} else {
|
||||
writeln!(f, "counts are disabled")
|
||||
};
|
||||
}
|
||||
let max_width =
|
||||
self.entries.iter().map(|(name, _count)| name.chars().count()).max().unwrap_or(0);
|
||||
for (name, counts) in &self.entries {
|
||||
writeln!(
|
||||
f,
|
||||
"{:<max_width$} {:>12} {:>12} {:>12}",
|
||||
name,
|
||||
sep(counts.total),
|
||||
sep(counts.max_live),
|
||||
sep(counts.live),
|
||||
max_width = max_width
|
||||
)?;
|
||||
}
|
||||
writeln!(
|
||||
f,
|
||||
"{:<max_width$} {:>12} {:>12} {:>12}",
|
||||
"",
|
||||
"total",
|
||||
"max_live",
|
||||
"live",
|
||||
max_width = max_width
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
30
third_party/crates/crates.bzl
vendored
30
third_party/crates/crates.bzl
vendored
@@ -310,11 +310,17 @@ def aliases(
|
||||
###############################################################################
|
||||
|
||||
_CRATE_EDITIONS = {
|
||||
"": "2018",
|
||||
"src/ariadne": "2024",
|
||||
"src/machoke": "2024",
|
||||
}
|
||||
|
||||
_NORMAL_DEPENDENCIES = {
|
||||
"": {
|
||||
_COMMON_CONDITION: {
|
||||
"rnix": Label("//third_party/crates/rnix-0.14.0:rnix"),
|
||||
},
|
||||
},
|
||||
"src/ariadne": {
|
||||
_COMMON_CONDITION: {
|
||||
"clap": Label("//third_party/crates/clap-4.6.6:clap"),
|
||||
@@ -327,6 +333,10 @@ _NORMAL_DEPENDENCIES = {
|
||||
}
|
||||
|
||||
_NORMAL_ALIASES = {
|
||||
"": {
|
||||
_COMMON_CONDITION: {
|
||||
},
|
||||
},
|
||||
"src/ariadne": {
|
||||
_COMMON_CONDITION: {
|
||||
},
|
||||
@@ -336,6 +346,8 @@ _NORMAL_ALIASES = {
|
||||
}
|
||||
|
||||
_NORMAL_DEV_DEPENDENCIES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -343,6 +355,8 @@ _NORMAL_DEV_DEPENDENCIES = {
|
||||
}
|
||||
|
||||
_NORMAL_DEV_ALIASES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -350,6 +364,8 @@ _NORMAL_DEV_ALIASES = {
|
||||
}
|
||||
|
||||
_PROC_MACRO_DEPENDENCIES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -357,6 +373,8 @@ _PROC_MACRO_DEPENDENCIES = {
|
||||
}
|
||||
|
||||
_PROC_MACRO_ALIASES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -364,6 +382,8 @@ _PROC_MACRO_ALIASES = {
|
||||
}
|
||||
|
||||
_PROC_MACRO_DEV_DEPENDENCIES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -371,6 +391,8 @@ _PROC_MACRO_DEV_DEPENDENCIES = {
|
||||
}
|
||||
|
||||
_PROC_MACRO_DEV_ALIASES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -378,6 +400,8 @@ _PROC_MACRO_DEV_ALIASES = {
|
||||
}
|
||||
|
||||
_BUILD_DEPENDENCIES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -385,6 +409,8 @@ _BUILD_DEPENDENCIES = {
|
||||
}
|
||||
|
||||
_BUILD_ALIASES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -392,6 +418,8 @@ _BUILD_ALIASES = {
|
||||
}
|
||||
|
||||
_BUILD_PROC_MACRO_DEPENDENCIES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
@@ -399,6 +427,8 @@ _BUILD_PROC_MACRO_DEPENDENCIES = {
|
||||
}
|
||||
|
||||
_BUILD_PROC_MACRO_ALIASES = {
|
||||
"": {
|
||||
},
|
||||
"src/ariadne": {
|
||||
},
|
||||
"src/machoke": {
|
||||
|
||||
1
third_party/crates/hashbrown-0.14.5/.cargo-checksum.json
vendored
Normal file
1
third_party/crates/hashbrown-0.14.5/.cargo-checksum.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"b1f17aefeca2e91526393fbf93f76ddb51f4c1693746a8f598bfb0f3444a7a6f","CHANGELOG.md":"1a844fe3b7466b41ca1d5914af197d5aeed7cb14f30ebe4be351367d7ca905d2","Cargo.toml":"c011f10385da722056537329f3fcf8c9b93af742e79e38885c0152a0105fc227","Cargo.toml.orig":"6d7350ae61b9df7a42e4e2293fbfa8cc5a7ab351732d45e178dcfc7b413d3819","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"84c222ce49510535419d338b7532a72a2bf22b7466e44de78d92d25b6c7d636b","benches/bench.rs":"ef7bc025922f077d307c565640c005d056e3d6c1713448a95aae92d3c22c1005","benches/insert_unique_unchecked.rs":"cb84275f22d5f95a5ac995ac6b2df74ffcf342765b401d27c95f2955c7b7cb9f","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"0625e6a5e3b8ecc8901a12aeeea54393fd84617fb3a14d98a34d2d2bddb8d257","src/external_trait_impls/rayon/helpers.rs":"ba105bf0853ebc45157f22116ad0f55d3bdab75e721d8e7a677c7b912d0c0c6d","src/external_trait_impls/rayon/map.rs":"96fdf39b3f601f77152d7ce84541b8f51f32b9274b7da9c294862892e721a5d8","src/external_trait_impls/rayon/mod.rs":"126edc882501dddd25e442d9236508b5b386eb8c0a9f5d654f2dd081086c1616","src/external_trait_impls/rayon/raw.rs":"04012fb2e99648819b4bc0044107ed3cb94013e242b7865075c5bd9ebf1b6865","src/external_trait_impls/rayon/set.rs":"7539348ff7bc6e3cce6b3c019d62dc401eea0138c578fef729c2593e8ead1cfa","src/external_trait_impls/rayon/table.rs":"8778d29509c68b5b7cb66859db025d3939ce22e7cf370b20ff3dea4fe4b29fd0","src/external_trait_impls/rkyv/hash_map.rs":"7abe24318143b776016052b05840656afc858b1ba5252f3d418d61972477f53d","src/external_trait_impls/rkyv/hash_set.rs":"38d969125d17d606492ec4ec9fc06b7e7118eb903240dacf40de21b9b06fa5c8","src/external_trait_impls/rkyv/mod.rs":"54399ce5574fd1d84b7b0cb4238fa3e898575e89a6724299be009d2172bda02e","src/external_trait_impls/serde.rs":"6dbe104dee16b453b6b048b541c6e02c6d067d970dfafd243fc4360288b0168c","src/lib.rs":"74e250c18e55994a4a902eaa06aca034559d6de53501ed4bf9010fabc67e88a2","src/macros.rs":"98a26b908fc0fbe6a58d008a317e550013d615eb3cc17a5054a573c62c1d74cb","src/map.rs":"d484f2f81e5b4acf4b615f187241e34c3016aaaca53a5e71019cceb993c4ebd7","src/raw/alloc.rs":"902f8588d0fdee3e5c3dc02410f41d4b38ac88843727387f929f3186b3a2d322","src/raw/bitmask.rs":"3b3dce8d6a48856ada19085abf43908f124ab3419fcf434b9ca64d7bff243f67","src/raw/generic.rs":"efc5e603be3e9a17935aef1836a38ce01c78a0093b2af0671548eb5459b37921","src/raw/mod.rs":"16bbabf42dde9f3fb17c4f7e768aef47752d839bf624b81d24a48af3d418b3a2","src/raw/neon.rs":"9907d8ebc36fc3df562dde478ea9b72213fda65288a304718d8647f0029dc9ad","src/raw/sse2.rs":"39038e3344e49f4638e211bcdbf56565ac53e90dce56172cc3b526fea911c2af","src/rustc_entry.rs":"8142ed89b50155602ef8c1628382bd62d3ee903920fe49d403d4100a278c6ba4","src/scopeguard.rs":"1a246e08a63c06cd8ad934bd7da229421bf804f991ae93cd7e242da27ca6c601","src/set.rs":"a620ed68bd1610b76c4c1890615d71b2c04928bf5b345133a0588a065bce06fa","src/table.rs":"7b7174099d2e3cade0caeddd73e29b7395f3b9f4f1f21013f885b52cd93438cb","tests/equivalent_trait.rs":"84faa3fe9d67c375d03fec81f0f1412c47862477d42e84e7d235258236338d5b","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/raw.rs":"43ed2f98877533a0905611d9a30f26b183dd3e103e3856eeab80e7b8ac7894d3","tests/rayon.rs":"39cb24ab45fce8087bb54948715c8b6973ebfba1a325292b5b3cd9aab50b5fd2","tests/serde.rs":"6bac8054db722dd049901b37a6e006535bac30f425eb5cd91af19b5bc1dfe78e","tests/set.rs":"9f8011c29d1059aadb54b6dd4623521d5178b4278b4a56021ef2cee4bbb19fd9"},"package":"e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"}
|
||||
6
third_party/crates/hashbrown-0.14.5/.cargo_vcs_info.json
vendored
Normal file
6
third_party/crates/hashbrown-0.14.5/.cargo_vcs_info.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "025d0f58b62d074f5fd660a22fe293cdc237d589"
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
113
third_party/crates/hashbrown-0.14.5/BUILD.bazel
vendored
Normal file
113
third_party/crates/hashbrown-0.14.5/BUILD.bazel
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
###############################################################################
|
||||
# @generated
|
||||
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
|
||||
# regenerate this file, run the following:
|
||||
#
|
||||
# bazel run @@//third_party:vendor_crates
|
||||
###############################################################################
|
||||
|
||||
load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars")
|
||||
load("@rules_rust//rust:defs.bzl", "rust_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cargo_toml_env_vars(
|
||||
name = "cargo_toml_env_vars",
|
||||
src = "Cargo.toml",
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "hashbrown",
|
||||
srcs = glob(
|
||||
include = ["**/*.rs"],
|
||||
allow_empty = False,
|
||||
),
|
||||
compile_data = glob(
|
||||
include = ["**"],
|
||||
allow_empty = True,
|
||||
exclude = [
|
||||
"**/* *",
|
||||
".tmp_git_root/**/*",
|
||||
"BUILD",
|
||||
"BUILD.bazel",
|
||||
"WORKSPACE",
|
||||
"WORKSPACE.bazel",
|
||||
],
|
||||
),
|
||||
crate_features = [
|
||||
"inline-more",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
edition = "2021",
|
||||
rustc_env_files = [
|
||||
":cargo_toml_env_vars",
|
||||
],
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-bazel",
|
||||
"crate-name=hashbrown",
|
||||
"manual",
|
||||
"noclippy",
|
||||
"norustfmt",
|
||||
],
|
||||
target_compatible_with = select({
|
||||
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios-macabi": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
|
||||
"@rules_rust//rust/platform:aarch64-linux-android": [],
|
||||
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-fuchsia": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-none": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-uefi": [],
|
||||
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
|
||||
"@rules_rust//rust/platform:arm-unknown-linux-musleabi": [],
|
||||
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
|
||||
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
|
||||
"@rules_rust//rust/platform:i686-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:i686-linux-android": [],
|
||||
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
|
||||
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:mips-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-netbsd": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-openbsd": [],
|
||||
"@rules_rust//rust/platform:thumbv6m-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv7em-none-eabihf": [],
|
||||
"@rules_rust//rust/platform:thumbv7m-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [],
|
||||
"@rules_rust//rust/platform:wasm32-unknown-emscripten": [],
|
||||
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip1": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip1-threads": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip2": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-ios": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-ios-macabi": [],
|
||||
"@rules_rust//rust/platform:x86_64-linux-android": [],
|
||||
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-fuchsia": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-none": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-uefi": [],
|
||||
"//conditions:default": ["@platforms//:incompatible"],
|
||||
}),
|
||||
version = "0.14.5",
|
||||
)
|
||||
532
third_party/crates/hashbrown-0.14.5/CHANGELOG.md
vendored
Normal file
532
third_party/crates/hashbrown-0.14.5/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,532 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed `hash_set::{Entry, VacantEntry}::insert` to return `OccupiedEntry`. (#495)
|
||||
|
||||
## [v0.14.5] - 2024-04-28
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed index calculation in panic guard of `clone_from_impl`. (#511)
|
||||
|
||||
## ~~[v0.14.4] - 2024-03-19~~
|
||||
|
||||
This release was _yanked_ due to a breaking change.
|
||||
|
||||
## [v0.14.3] - 2023-11-26
|
||||
|
||||
### Added
|
||||
|
||||
- Specialized `fold` implementation of iterators. (#480)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Avoid using unstable `ptr::invalid_mut` on nightly. (#481)
|
||||
|
||||
## [v0.14.2] - 2023-10-19
|
||||
|
||||
### Added
|
||||
|
||||
- `HashTable` type which provides a low-level but safe API with explicit hashing. (#466)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Disabled the use of NEON instructions on big-endian ARM. (#475)
|
||||
- Disabled the use of NEON instructions on Miri. (#476)
|
||||
|
||||
## [v0.14.1] - 2023-09-28
|
||||
|
||||
### Added
|
||||
|
||||
- Allow serializing `HashMap`s that use a custom allocator. (#449)
|
||||
|
||||
### Changed
|
||||
|
||||
- Use the `Equivalent` trait from the `equivalent` crate. (#442)
|
||||
- Slightly improved performance of table resizing. (#451)
|
||||
- Relaxed MSRV to 1.63.0. (#457)
|
||||
- Removed `Clone` requirement from custom allocators. (#468)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed custom allocators being leaked in some situations. (#439, #465)
|
||||
|
||||
## [v0.14.0] - 2023-06-01
|
||||
|
||||
### Added
|
||||
|
||||
- Support for `allocator-api2` crate
|
||||
for interfacing with custom allocators on stable. (#417)
|
||||
- Optimized implementation for ARM using NEON instructions. (#430)
|
||||
- Support for rkyv serialization. (#432)
|
||||
- `Equivalent` trait to look up values without `Borrow`. (#345)
|
||||
- `Hash{Map,Set}::raw_table_mut` is added whic returns a mutable reference. (#404)
|
||||
- Fast path for `clear` on empty tables. (#428)
|
||||
|
||||
### Changed
|
||||
|
||||
- Optimized insertion to only perform a single lookup. (#277)
|
||||
- `DrainFilter` (`drain_filter`) has been renamed to `ExtractIf` and no longer drops remaining
|
||||
elements when the iterator is dropped. #(374)
|
||||
- Bumped MSRV to 1.64.0. (#431)
|
||||
- `{Map,Set}::raw_table` now returns an immutable reference. (#404)
|
||||
- `VacantEntry` and `OccupiedEntry` now use the default hasher if none is
|
||||
specified in generics. (#389)
|
||||
- `RawTable::data_start` now returns a `NonNull` to match `RawTable::data_end`. (#387)
|
||||
- `RawIter::{reflect_insert, reflect_remove}` are now unsafe. (#429)
|
||||
- `RawTable::find_potential` is renamed to `find_or_find_insert_slot` and returns an `InsertSlot`. (#429)
|
||||
- `RawTable::remove` now also returns an `InsertSlot`. (#429)
|
||||
- `InsertSlot` can be used to insert an element with `RawTable::insert_in_slot`. (#429)
|
||||
- `RawIterHash` no longer has a lifetime tied to that of the `RawTable`. (#427)
|
||||
- The trait bounds of `HashSet::raw_table` have been relaxed to not require `Eq + Hash`. (#423)
|
||||
- `EntryRef::and_replace_entry_with` and `OccupiedEntryRef::replace_entry_with`
|
||||
were changed to give a `&K` instead of a `&Q` to the closure.
|
||||
|
||||
### Removed
|
||||
|
||||
- Support for `bumpalo` as an allocator with custom wrapper.
|
||||
Use `allocator-api2` feature in `bumpalo` to use it as an allocator
|
||||
for `hashbrown` collections. (#417)
|
||||
|
||||
## [v0.13.2] - 2023-01-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Added `#[inline(always)]` to `find_inner`. (#375)
|
||||
- Fixed `RawTable::allocation_info` for empty tables. (#376)
|
||||
|
||||
## [v0.13.1] - 2022-11-10
|
||||
|
||||
### Added
|
||||
|
||||
- Added `Equivalent` trait to customize key lookups. (#350)
|
||||
- Added support for 16-bit targets. (#368)
|
||||
- Added `RawTable::allocation_info` which provides information about the memory
|
||||
usage of a table. (#371)
|
||||
|
||||
### Changed
|
||||
|
||||
- Bumped MSRV to 1.61.0.
|
||||
- Upgraded to `ahash` 0.8. (#357)
|
||||
- Make `with_hasher_in` const. (#355)
|
||||
- The following methods have been removed from the `RawTable` API in favor of
|
||||
safer alternatives:
|
||||
- `RawTable::erase_no_drop` => Use `RawTable::erase` or `RawTable::remove` instead.
|
||||
- `Bucket::read` => Use `RawTable::remove` instead.
|
||||
- `Bucket::drop` => Use `RawTable::erase` instead.
|
||||
- `Bucket::write` => Use `Bucket::as_mut` instead.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Ensure that `HashMap` allocations don't exceed `isize::MAX`. (#362)
|
||||
- Fixed issue with field retagging in scopeguard. (#359)
|
||||
|
||||
## [v0.12.3] - 2022-07-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed double-drop in `RawTable::clone_from`. (#348)
|
||||
|
||||
## [v0.12.2] - 2022-07-09
|
||||
|
||||
### Added
|
||||
|
||||
- Added `Entry` API for `HashSet`. (#342)
|
||||
- Added `Extend<&'a (K, V)> for HashMap<K, V, S, A>`. (#340)
|
||||
- Added length-based short-circuiting for hash table iteration. (#338)
|
||||
- Added a function to access the `RawTable` of a `HashMap`. (#335)
|
||||
|
||||
### Changed
|
||||
|
||||
- Edited `do_alloc` to reduce LLVM IR generated. (#341)
|
||||
|
||||
## [v0.12.1] - 2022-05-02
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed underflow in `RawIterRange::size_hint`. (#325)
|
||||
- Fixed the implementation of `Debug` for `ValuesMut` and `IntoValues`. (#325)
|
||||
|
||||
## [v0.12.0] - 2022-01-17
|
||||
|
||||
### Added
|
||||
|
||||
- Added `From<[T; N]>` and `From<[(K, V); N]>` for `HashSet` and `HashMap` respectively. (#297)
|
||||
- Added an `allocator()` getter to HashMap and HashSet. (#257)
|
||||
- Added `insert_unique_unchecked` to `HashMap` and `HashSet`. (#293)
|
||||
- Added `into_keys` and `into_values` to HashMap. (#295)
|
||||
- Implement `From<array>` on `HashSet` and `HashMap`. (#298)
|
||||
- Added `entry_ref` API to `HashMap`. (#201)
|
||||
|
||||
### Changed
|
||||
|
||||
- Bumped minimum Rust version to 1.56.1 and edition to 2021.
|
||||
- Use u64 for the GroupWord on WebAssembly. (#271)
|
||||
- Optimized `find`. (#279)
|
||||
- Made rehashing and resizing less generic to reduce compilation time. (#282)
|
||||
- Inlined small functions. (#283)
|
||||
- Use `BuildHasher::hash_one` when `feature = "nightly"` is enabled. (#292)
|
||||
- Relaxed the bounds on `Debug` for `HashSet`. (#296)
|
||||
- Rename `get_each_mut` to `get_many_mut` and align API with the stdlib. (#291)
|
||||
- Don't hash the key when searching in an empty table. (#305)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Guard against allocations exceeding isize::MAX. (#268)
|
||||
- Made `RawTable::insert_no_grow` unsafe. (#254)
|
||||
- Inline `static_empty`. (#280)
|
||||
- Fixed trait bounds on Send/Sync impls. (#303)
|
||||
|
||||
## [v0.11.2] - 2021-03-25
|
||||
|
||||
### Fixed
|
||||
|
||||
- Added missing allocator type parameter to `HashMap`'s and `HashSet`'s `Clone` impls. (#252)
|
||||
|
||||
## [v0.11.1] - 2021-03-20
|
||||
|
||||
### Fixed
|
||||
|
||||
- Added missing `pub` modifier to `BumpWrapper`. (#251)
|
||||
|
||||
## [v0.11.0] - 2021-03-14
|
||||
|
||||
### Added
|
||||
- Added safe `try_insert_no_grow` method to `RawTable`. (#229)
|
||||
- Added support for `bumpalo` as an allocator without the `nightly` feature. (#231)
|
||||
- Implemented `Default` for `RawTable`. (#237)
|
||||
- Added new safe methods `RawTable::get_each_mut`, `HashMap::get_each_mut`, and
|
||||
`HashMap::get_each_key_value_mut`. (#239)
|
||||
- Added `From<HashMap<T, ()>>` for `HashSet<T>`. (#235)
|
||||
- Added `try_insert` method to `HashMap`. (#247)
|
||||
|
||||
### Changed
|
||||
- The minimum Rust version has been bumped to 1.49.0. (#230)
|
||||
- Significantly improved compilation times by reducing the amount of generated IR. (#205)
|
||||
|
||||
### Removed
|
||||
- We no longer re-export the unstable allocator items from the standard library, nor the stable shims approximating the same. (#227)
|
||||
- Removed hasher specialization support from `aHash`, which was resulting in inconsistent hashes being generated for a key. (#248)
|
||||
|
||||
### Fixed
|
||||
- Fixed union length comparison. (#228)
|
||||
|
||||
## ~~[v0.10.0] - 2021-01-16~~
|
||||
|
||||
This release was _yanked_ due to inconsistent hashes being generated with the `nightly` feature. (#248)
|
||||
|
||||
### Changed
|
||||
- Parametrized `RawTable`, `HashSet` and `HashMap` over an allocator. (#133)
|
||||
- Improved branch prediction hints on stable. (#209)
|
||||
- Optimized hashing of primitive types with AHash using specialization. (#207)
|
||||
- Only instantiate `RawTable`'s reserve functions once per key-value. (#204)
|
||||
|
||||
## [v0.9.1] - 2020-09-28
|
||||
|
||||
### Added
|
||||
- Added safe methods to `RawTable` (#202):
|
||||
- `get`: `find` and `as_ref`
|
||||
- `get_mut`: `find` and `as_mut`
|
||||
- `insert_entry`: `insert` and `as_mut`
|
||||
- `remove_entry`: `find` and `remove`
|
||||
- `erase_entry`: `find` and `erase`
|
||||
|
||||
### Changed
|
||||
- Removed `from_key_hashed_nocheck`'s `Q: Hash`. (#200)
|
||||
- Made `RawTable::drain` safe. (#201)
|
||||
|
||||
## [v0.9.0] - 2020-09-03
|
||||
|
||||
### Fixed
|
||||
- `drain_filter` now removes and yields items that do match the predicate,
|
||||
rather than items that don't. This is a **breaking change** to match the
|
||||
behavior of the `drain_filter` methods in `std`. (#187)
|
||||
|
||||
### Added
|
||||
- Added `replace_entry_with` to `OccupiedEntry`, and `and_replace_entry_with` to `Entry`. (#190)
|
||||
- Implemented `FusedIterator` and `size_hint` for `DrainFilter`. (#188)
|
||||
|
||||
### Changed
|
||||
- The minimum Rust version has been bumped to 1.36 (due to `crossbeam` dependency). (#193)
|
||||
- Updated `ahash` dependency to 0.4. (#198)
|
||||
- `HashMap::with_hasher` and `HashSet::with_hasher` are now `const fn`. (#195)
|
||||
- Removed `T: Hash + Eq` and `S: BuildHasher` bounds on `HashSet::new`,
|
||||
`with_capacity`, `with_hasher`, and `with_capacity_and_hasher`. (#185)
|
||||
|
||||
## [v0.8.2] - 2020-08-08
|
||||
|
||||
### Changed
|
||||
- Avoid closures to improve compile times. (#183)
|
||||
- Do not iterate to drop if empty. (#182)
|
||||
|
||||
## [v0.8.1] - 2020-07-16
|
||||
|
||||
### Added
|
||||
- Added `erase` and `remove` to `RawTable`. (#171)
|
||||
- Added `try_with_capacity` to `RawTable`. (#174)
|
||||
- Added methods that allow re-using a `RawIter` for `RawDrain`,
|
||||
`RawIntoIter`, and `RawParIter`. (#175)
|
||||
- Added `reflect_remove` and `reflect_insert` to `RawIter`. (#175)
|
||||
- Added a `drain_filter` function to `HashSet`. (#179)
|
||||
|
||||
### Changed
|
||||
- Deprecated `RawTable::erase_no_drop` in favor of `erase` and `remove`. (#176)
|
||||
- `insert_no_grow` is now exposed under the `"raw"` feature. (#180)
|
||||
|
||||
## [v0.8.0] - 2020-06-18
|
||||
|
||||
### Fixed
|
||||
- Marked `RawTable::par_iter` as `unsafe`. (#157)
|
||||
|
||||
### Changed
|
||||
- Reduced the size of `HashMap`. (#159)
|
||||
- No longer create tables with a capacity of 1 element. (#162)
|
||||
- Removed `K: Eq + Hash` bounds on `retain`. (#163)
|
||||
- Pulled in `HashMap` changes from rust-lang/rust (#164):
|
||||
- `extend_one` support on nightly.
|
||||
- `CollectionAllocErr` renamed to `TryReserveError`.
|
||||
- Added `HashSet::get_or_insert_owned`.
|
||||
- `Default` for `HashSet` no longer requires `T: Eq + Hash` and `S: BuildHasher`.
|
||||
|
||||
## [v0.7.2] - 2020-04-27
|
||||
|
||||
### Added
|
||||
- Added `or_insert_with_key` to `Entry`. (#152)
|
||||
|
||||
### Fixed
|
||||
- Partially reverted `Clone` optimization which was unsound. (#154)
|
||||
|
||||
### Changed
|
||||
- Disabled use of `const-random` by default, which prevented reproducible builds. (#155)
|
||||
- Optimized `repeat` function. (#150)
|
||||
- Use `NonNull` for buckets, which improves codegen for iterators. (#148)
|
||||
|
||||
## [v0.7.1] - 2020-03-16
|
||||
|
||||
### Added
|
||||
- Added `HashMap::get_key_value_mut`. (#145)
|
||||
|
||||
### Changed
|
||||
- Optimized `Clone` implementation. (#146)
|
||||
|
||||
## [v0.7.0] - 2020-01-31
|
||||
|
||||
### Added
|
||||
- Added a `drain_filter` function to `HashMap`. (#135)
|
||||
|
||||
### Changed
|
||||
- Updated `ahash` dependency to 0.3. (#141)
|
||||
- Optimized set union and intersection. (#130)
|
||||
- `raw_entry` can now be used without requiring `S: BuildHasher`. (#123)
|
||||
- `RawTable::bucket_index` can now be used under the `raw` feature. (#128)
|
||||
|
||||
## [v0.6.3] - 2019-10-31
|
||||
|
||||
### Added
|
||||
- Added an `ahash-compile-time-rng` feature (enabled by default) which allows disabling the
|
||||
`compile-time-rng` feature in `ahash` to work around a Cargo bug. (#125)
|
||||
|
||||
## [v0.6.2] - 2019-10-23
|
||||
|
||||
### Added
|
||||
- Added an `inline-more` feature (enabled by default) which allows choosing a tradeoff between
|
||||
runtime performance and compilation time. (#119)
|
||||
|
||||
## [v0.6.1] - 2019-10-04
|
||||
|
||||
### Added
|
||||
- Added `Entry::insert` and `RawEntryMut::insert`. (#118)
|
||||
|
||||
### Changed
|
||||
- `Group::static_empty` was changed from a `const` to a `static` (#116).
|
||||
|
||||
## [v0.6.0] - 2019-08-13
|
||||
|
||||
### Fixed
|
||||
- Fixed AHash accidentally depending on `std`. (#110)
|
||||
|
||||
### Changed
|
||||
- The minimum Rust version has been bumped to 1.32 (due to `rand` dependency).
|
||||
|
||||
## ~~[v0.5.1] - 2019-08-04~~
|
||||
|
||||
This release was _yanked_ due to a breaking change for users of `no-default-features`.
|
||||
|
||||
### Added
|
||||
- The experimental and unsafe `RawTable` API is available under the "raw" feature. (#108)
|
||||
- Added entry-like methods for `HashSet`. (#98)
|
||||
|
||||
### Changed
|
||||
- Changed the default hasher from FxHash to AHash. (#97)
|
||||
- `hashbrown` is now fully `no_std` on recent Rust versions (1.36+). (#96)
|
||||
|
||||
### Fixed
|
||||
- We now avoid growing the table during insertions when it wasn't necessary. (#106)
|
||||
- `RawOccupiedEntryMut` now properly implements `Send` and `Sync`. (#100)
|
||||
- Relaxed `lazy_static` version. (#92)
|
||||
|
||||
## [v0.5.0] - 2019-06-12
|
||||
|
||||
### Fixed
|
||||
- Resize with a more conservative amount of space after deletions. (#86)
|
||||
|
||||
### Changed
|
||||
- Exposed the Layout of the failed allocation in CollectionAllocErr::AllocErr. (#89)
|
||||
|
||||
## [v0.4.0] - 2019-05-30
|
||||
|
||||
### Fixed
|
||||
- Fixed `Send` trait bounds on `IterMut` not matching the libstd one. (#82)
|
||||
|
||||
## [v0.3.1] - 2019-05-30
|
||||
|
||||
### Fixed
|
||||
- Fixed incorrect use of slice in unsafe code. (#80)
|
||||
|
||||
## [v0.3.0] - 2019-04-23
|
||||
|
||||
### Changed
|
||||
- Changed shrink_to to not panic if min_capacity < capacity. (#67)
|
||||
|
||||
### Fixed
|
||||
- Worked around emscripten bug emscripten-core/emscripten-fastcomp#258. (#66)
|
||||
|
||||
## [v0.2.2] - 2019-04-16
|
||||
|
||||
### Fixed
|
||||
- Inlined non-nightly lowest_set_bit_nonzero. (#64)
|
||||
- Fixed build on latest nightly. (#65)
|
||||
|
||||
## [v0.2.1] - 2019-04-14
|
||||
|
||||
### Changed
|
||||
- Use for_each in map Extend and FromIterator. (#58)
|
||||
- Improved worst-case performance of HashSet.is_subset. (#61)
|
||||
|
||||
### Fixed
|
||||
- Removed incorrect debug_assert. (#60)
|
||||
|
||||
## [v0.2.0] - 2019-03-31
|
||||
|
||||
### Changed
|
||||
- The code has been updated to Rust 2018 edition. This means that the minimum
|
||||
Rust version has been bumped to 1.31 (2018 edition).
|
||||
|
||||
### Added
|
||||
- Added `insert_with_hasher` to the raw_entry API to allow `K: !(Hash + Eq)`. (#54)
|
||||
- Added support for using hashbrown as the hash table implementation in libstd. (#46)
|
||||
|
||||
### Fixed
|
||||
- Fixed cargo build with minimal-versions. (#45)
|
||||
- Fixed `#[may_dangle]` attributes to match the libstd `HashMap`. (#46)
|
||||
- ZST keys and values are now handled properly. (#46)
|
||||
|
||||
## [v0.1.8] - 2019-01-14
|
||||
|
||||
### Added
|
||||
- Rayon parallel iterator support (#37)
|
||||
- `raw_entry` support (#31)
|
||||
- `#[may_dangle]` on nightly (#31)
|
||||
- `try_reserve` support (#31)
|
||||
|
||||
### Fixed
|
||||
- Fixed variance on `IterMut`. (#31)
|
||||
|
||||
## [v0.1.7] - 2018-12-05
|
||||
|
||||
### Fixed
|
||||
- Fixed non-SSE version of convert_special_to_empty_and_full_to_deleted. (#32)
|
||||
- Fixed overflow in rehash_in_place. (#33)
|
||||
|
||||
## [v0.1.6] - 2018-11-17
|
||||
|
||||
### Fixed
|
||||
- Fixed compile error on nightly. (#29)
|
||||
|
||||
## [v0.1.5] - 2018-11-08
|
||||
|
||||
### Fixed
|
||||
- Fixed subtraction overflow in generic::Group::match_byte. (#28)
|
||||
|
||||
## [v0.1.4] - 2018-11-04
|
||||
|
||||
### Fixed
|
||||
- Fixed a bug in the `erase_no_drop` implementation. (#26)
|
||||
|
||||
## [v0.1.3] - 2018-11-01
|
||||
|
||||
### Added
|
||||
- Serde support. (#14)
|
||||
|
||||
### Fixed
|
||||
- Make the compiler inline functions more aggressively. (#20)
|
||||
|
||||
## [v0.1.2] - 2018-10-31
|
||||
|
||||
### Fixed
|
||||
- `clear` segfaults when called on an empty table. (#13)
|
||||
|
||||
## [v0.1.1] - 2018-10-30
|
||||
|
||||
### Fixed
|
||||
- `erase_no_drop` optimization not triggering in the SSE2 implementation. (#3)
|
||||
- Missing `Send` and `Sync` for hash map and iterator types. (#7)
|
||||
- Bug when inserting into a table smaller than the group width. (#5)
|
||||
|
||||
## v0.1.0 - 2018-10-29
|
||||
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.14.5...HEAD
|
||||
[v0.14.5]: https://github.com/rust-lang/hashbrown/compare/v0.14.4...v0.14.5
|
||||
[v0.14.4]: https://github.com/rust-lang/hashbrown/compare/v0.14.3...v0.14.4
|
||||
[v0.14.3]: https://github.com/rust-lang/hashbrown/compare/v0.14.2...v0.14.3
|
||||
[v0.14.2]: https://github.com/rust-lang/hashbrown/compare/v0.14.1...v0.14.2
|
||||
[v0.14.1]: https://github.com/rust-lang/hashbrown/compare/v0.14.0...v0.14.1
|
||||
[v0.14.0]: https://github.com/rust-lang/hashbrown/compare/v0.13.2...v0.14.0
|
||||
[v0.13.2]: https://github.com/rust-lang/hashbrown/compare/v0.13.1...v0.13.2
|
||||
[v0.13.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.3...v0.13.1
|
||||
[v0.12.3]: https://github.com/rust-lang/hashbrown/compare/v0.12.2...v0.12.3
|
||||
[v0.12.2]: https://github.com/rust-lang/hashbrown/compare/v0.12.1...v0.12.2
|
||||
[v0.12.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.0...v0.12.1
|
||||
[v0.12.0]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...v0.12.0
|
||||
[v0.11.2]: https://github.com/rust-lang/hashbrown/compare/v0.11.1...v0.11.2
|
||||
[v0.11.1]: https://github.com/rust-lang/hashbrown/compare/v0.11.0...v0.11.1
|
||||
[v0.11.0]: https://github.com/rust-lang/hashbrown/compare/v0.10.0...v0.11.0
|
||||
[v0.10.0]: https://github.com/rust-lang/hashbrown/compare/v0.9.1...v0.10.0
|
||||
[v0.9.1]: https://github.com/rust-lang/hashbrown/compare/v0.9.0...v0.9.1
|
||||
[v0.9.0]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...v0.9.0
|
||||
[v0.8.2]: https://github.com/rust-lang/hashbrown/compare/v0.8.1...v0.8.2
|
||||
[v0.8.1]: https://github.com/rust-lang/hashbrown/compare/v0.8.0...v0.8.1
|
||||
[v0.8.0]: https://github.com/rust-lang/hashbrown/compare/v0.7.2...v0.8.0
|
||||
[v0.7.2]: https://github.com/rust-lang/hashbrown/compare/v0.7.1...v0.7.2
|
||||
[v0.7.1]: https://github.com/rust-lang/hashbrown/compare/v0.7.0...v0.7.1
|
||||
[v0.7.0]: https://github.com/rust-lang/hashbrown/compare/v0.6.3...v0.7.0
|
||||
[v0.6.3]: https://github.com/rust-lang/hashbrown/compare/v0.6.2...v0.6.3
|
||||
[v0.6.2]: https://github.com/rust-lang/hashbrown/compare/v0.6.1...v0.6.2
|
||||
[v0.6.1]: https://github.com/rust-lang/hashbrown/compare/v0.6.0...v0.6.1
|
||||
[v0.6.0]: https://github.com/rust-lang/hashbrown/compare/v0.5.1...v0.6.0
|
||||
[v0.5.1]: https://github.com/rust-lang/hashbrown/compare/v0.5.0...v0.5.1
|
||||
[v0.5.0]: https://github.com/rust-lang/hashbrown/compare/v0.4.0...v0.5.0
|
||||
[v0.4.0]: https://github.com/rust-lang/hashbrown/compare/v0.3.1...v0.4.0
|
||||
[v0.3.1]: https://github.com/rust-lang/hashbrown/compare/v0.3.0...v0.3.1
|
||||
[v0.3.0]: https://github.com/rust-lang/hashbrown/compare/v0.2.2...v0.3.0
|
||||
[v0.2.2]: https://github.com/rust-lang/hashbrown/compare/v0.2.1...v0.2.2
|
||||
[v0.2.1]: https://github.com/rust-lang/hashbrown/compare/v0.2.0...v0.2.1
|
||||
[v0.2.0]: https://github.com/rust-lang/hashbrown/compare/v0.1.8...v0.2.0
|
||||
[v0.1.8]: https://github.com/rust-lang/hashbrown/compare/v0.1.7...v0.1.8
|
||||
[v0.1.7]: https://github.com/rust-lang/hashbrown/compare/v0.1.6...v0.1.7
|
||||
[v0.1.6]: https://github.com/rust-lang/hashbrown/compare/v0.1.5...v0.1.6
|
||||
[v0.1.5]: https://github.com/rust-lang/hashbrown/compare/v0.1.4...v0.1.5
|
||||
[v0.1.4]: https://github.com/rust-lang/hashbrown/compare/v0.1.3...v0.1.4
|
||||
[v0.1.3]: https://github.com/rust-lang/hashbrown/compare/v0.1.2...v0.1.3
|
||||
[v0.1.2]: https://github.com/rust-lang/hashbrown/compare/v0.1.1...v0.1.2
|
||||
[v0.1.1]: https://github.com/rust-lang/hashbrown/compare/v0.1.0...v0.1.1
|
||||
137
third_party/crates/hashbrown-0.14.5/Cargo.toml
vendored
Normal file
137
third_party/crates/hashbrown-0.14.5/Cargo.toml
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
# 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.63.0"
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
|
||||
exclude = [
|
||||
".github",
|
||||
"/ci/*",
|
||||
]
|
||||
description = "A Rust port of Google's SwissTable hash map"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"hash",
|
||||
"no_std",
|
||||
"hashmap",
|
||||
"swisstable",
|
||||
]
|
||||
categories = [
|
||||
"data-structures",
|
||||
"no-std",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-lang/hashbrown"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = [
|
||||
"nightly",
|
||||
"rayon",
|
||||
"serde",
|
||||
"raw",
|
||||
]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[dependencies.ahash]
|
||||
version = "0.8.7"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.alloc]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-alloc"
|
||||
|
||||
[dependencies.allocator-api2]
|
||||
version = "0.2.9"
|
||||
features = ["alloc"]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
version = "0.1.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.core]
|
||||
version = "1.0.0"
|
||||
optional = true
|
||||
package = "rustc-std-workspace-core"
|
||||
|
||||
[dependencies.equivalent]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.rayon]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.rkyv]
|
||||
version = "0.7.42"
|
||||
features = ["alloc"]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.25"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.bumpalo]
|
||||
version = "3.13.0"
|
||||
features = ["allocator-api2"]
|
||||
|
||||
[dev-dependencies.doc-comment]
|
||||
version = "0.3.1"
|
||||
|
||||
[dev-dependencies.fnv]
|
||||
version = "1.0.7"
|
||||
|
||||
[dev-dependencies.lazy_static]
|
||||
version = "1.4"
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.8.3"
|
||||
features = ["small_rng"]
|
||||
|
||||
[dev-dependencies.rayon]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.rkyv]
|
||||
version = "0.7.42"
|
||||
features = ["validation"]
|
||||
|
||||
[dev-dependencies.serde_test]
|
||||
version = "1.0"
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"ahash",
|
||||
"inline-more",
|
||||
"allocator-api2",
|
||||
]
|
||||
inline-more = []
|
||||
nightly = [
|
||||
"allocator-api2?/nightly",
|
||||
"bumpalo/allocator_api",
|
||||
]
|
||||
raw = []
|
||||
rustc-dep-of-std = [
|
||||
"nightly",
|
||||
"core",
|
||||
"compiler_builtins",
|
||||
"alloc",
|
||||
"rustc-internal-api",
|
||||
]
|
||||
rustc-internal-api = []
|
||||
71
third_party/crates/hashbrown-0.14.5/Cargo.toml.orig
generated
vendored
Normal file
71
third_party/crates/hashbrown-0.14.5/Cargo.toml.orig
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
[package]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
|
||||
description = "A Rust port of Google's SwissTable hash map"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-lang/hashbrown"
|
||||
readme = "README.md"
|
||||
keywords = ["hash", "no_std", "hashmap", "swisstable"]
|
||||
categories = ["data-structures", "no-std"]
|
||||
exclude = [".github", "/ci/*"]
|
||||
edition = "2021"
|
||||
rust-version = "1.63.0"
|
||||
|
||||
[dependencies]
|
||||
# For the default hasher
|
||||
ahash = { version = "0.8.7", default-features = false, optional = true }
|
||||
|
||||
# For external trait impls
|
||||
rayon = { version = "1.0", optional = true }
|
||||
serde = { version = "1.0.25", default-features = false, optional = true }
|
||||
rkyv = { version = "0.7.42", optional = true, default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
|
||||
# When built as part of libstd
|
||||
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
|
||||
compiler_builtins = { version = "0.1.2", optional = true }
|
||||
alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
|
||||
|
||||
# Support for allocators that use allocator-api2
|
||||
allocator-api2 = { version = "0.2.9", optional = true, default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
|
||||
# Equivalent trait which can be shared with other hash table implementations.
|
||||
equivalent = { version = "1.0", optional = true, default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4"
|
||||
rand = { version = "0.8.3", features = ["small_rng"] }
|
||||
rayon = "1.0"
|
||||
fnv = "1.0.7"
|
||||
serde_test = "1.0"
|
||||
doc-comment = "0.3.1"
|
||||
bumpalo = { version = "3.13.0", features = ["allocator-api2"] }
|
||||
rkyv = { version = "0.7.42", features = ["validation"] }
|
||||
|
||||
[features]
|
||||
default = ["ahash", "inline-more", "allocator-api2"]
|
||||
|
||||
nightly = ["allocator-api2?/nightly", "bumpalo/allocator_api"]
|
||||
|
||||
rustc-internal-api = []
|
||||
rustc-dep-of-std = [
|
||||
"nightly",
|
||||
"core",
|
||||
"compiler_builtins",
|
||||
"alloc",
|
||||
"rustc-internal-api",
|
||||
]
|
||||
raw = []
|
||||
|
||||
# Enables usage of `#[inline]` on far more functions than by default in this
|
||||
# crate. This may lead to a performance increase but often comes at a compile
|
||||
# time cost.
|
||||
inline-more = []
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["nightly", "rayon", "serde", "raw"]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
201
third_party/crates/hashbrown-0.14.5/LICENSE-APACHE
vendored
Normal file
201
third_party/crates/hashbrown-0.14.5/LICENSE-APACHE
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
third_party/crates/hashbrown-0.14.5/LICENSE-MIT
vendored
Normal file
25
third_party/crates/hashbrown-0.14.5/LICENSE-MIT
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2016 Amanieu d'Antras
|
||||
|
||||
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.
|
||||
125
third_party/crates/hashbrown-0.14.5/README.md
vendored
Normal file
125
third_party/crates/hashbrown-0.14.5/README.md
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
hashbrown
|
||||
=========
|
||||
|
||||
[](https://github.com/rust-lang/hashbrown/actions)
|
||||
[](https://crates.io/crates/hashbrown)
|
||||
[](https://docs.rs/hashbrown)
|
||||
[](https://github.com/rust-lang/hashbrown)
|
||||
|
||||
This crate is a Rust port of Google's high-performance [SwissTable] hash
|
||||
map, adapted to make it a drop-in replacement for Rust's standard `HashMap`
|
||||
and `HashSet` types.
|
||||
|
||||
The original C++ version of SwissTable can be found [here], and this
|
||||
[CppCon talk] gives an overview of how the algorithm works.
|
||||
|
||||
Since Rust 1.36, this is now the `HashMap` implementation for the Rust standard
|
||||
library. However you may still want to use this crate instead since it works
|
||||
in environments without `std`, such as embedded systems and kernels.
|
||||
|
||||
[SwissTable]: https://abseil.io/blog/20180927-swisstables
|
||||
[here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h
|
||||
[CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4
|
||||
|
||||
## [Change log](CHANGELOG.md)
|
||||
|
||||
## Features
|
||||
|
||||
- Drop-in replacement for the standard library `HashMap` and `HashSet` types.
|
||||
- Uses [AHash](https://github.com/tkaitchuck/aHash) as the default hasher, which is much faster than SipHash.
|
||||
However, AHash does *not provide the same level of HashDoS resistance* as SipHash, so if that is important to you, you might want to consider using a different hasher.
|
||||
- Around 2x faster than the previous standard library `HashMap`.
|
||||
- Lower memory usage: only 1 byte of overhead per entry instead of 8.
|
||||
- Compatible with `#[no_std]` (but requires a global allocator with the `alloc` crate).
|
||||
- Empty hash maps do not allocate any memory.
|
||||
- SIMD lookups to scan multiple hash entries in parallel.
|
||||
|
||||
## Performance
|
||||
|
||||
Compared to the previous implementation of `std::collections::HashMap` (Rust 1.35).
|
||||
|
||||
With the hashbrown default AHash hasher:
|
||||
|
||||
| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup |
|
||||
| :-------------------------- | :----------------: | ----------------: | :----------: | ------: | ------- |
|
||||
| insert_ahash_highbits | 18,865 | 8,020 | -10,845 | -57.49% | x 2.35 |
|
||||
| insert_ahash_random | 19,711 | 8,019 | -11,692 | -59.32% | x 2.46 |
|
||||
| insert_ahash_serial | 19,365 | 6,463 | -12,902 | -66.63% | x 3.00 |
|
||||
| insert_erase_ahash_highbits | 51,136 | 17,916 | -33,220 | -64.96% | x 2.85 |
|
||||
| insert_erase_ahash_random | 51,157 | 17,688 | -33,469 | -65.42% | x 2.89 |
|
||||
| insert_erase_ahash_serial | 45,479 | 14,895 | -30,584 | -67.25% | x 3.05 |
|
||||
| iter_ahash_highbits | 1,399 | 1,092 | -307 | -21.94% | x 1.28 |
|
||||
| iter_ahash_random | 1,586 | 1,059 | -527 | -33.23% | x 1.50 |
|
||||
| iter_ahash_serial | 3,168 | 1,079 | -2,089 | -65.94% | x 2.94 |
|
||||
| lookup_ahash_highbits | 32,351 | 4,792 | -27,559 | -85.19% | x 6.75 |
|
||||
| lookup_ahash_random | 17,419 | 4,817 | -12,602 | -72.35% | x 3.62 |
|
||||
| lookup_ahash_serial | 15,254 | 3,606 | -11,648 | -76.36% | x 4.23 |
|
||||
| lookup_fail_ahash_highbits | 21,187 | 4,369 | -16,818 | -79.38% | x 4.85 |
|
||||
| lookup_fail_ahash_random | 21,550 | 4,395 | -17,155 | -79.61% | x 4.90 |
|
||||
| lookup_fail_ahash_serial | 19,450 | 3,176 | -16,274 | -83.67% | x 6.12 |
|
||||
|
||||
|
||||
With the libstd default SipHash hasher:
|
||||
|
||||
| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup |
|
||||
| :------------------------ | :----------------: | ----------------: | :----------: | ------: | ------- |
|
||||
| insert_std_highbits | 19,216 | 16,885 | -2,331 | -12.13% | x 1.14 |
|
||||
| insert_std_random | 19,179 | 17,034 | -2,145 | -11.18% | x 1.13 |
|
||||
| insert_std_serial | 19,462 | 17,493 | -1,969 | -10.12% | x 1.11 |
|
||||
| insert_erase_std_highbits | 50,825 | 35,847 | -14,978 | -29.47% | x 1.42 |
|
||||
| insert_erase_std_random | 51,448 | 35,392 | -16,056 | -31.21% | x 1.45 |
|
||||
| insert_erase_std_serial | 87,711 | 38,091 | -49,620 | -56.57% | x 2.30 |
|
||||
| iter_std_highbits | 1,378 | 1,159 | -219 | -15.89% | x 1.19 |
|
||||
| iter_std_random | 1,395 | 1,132 | -263 | -18.85% | x 1.23 |
|
||||
| iter_std_serial | 1,704 | 1,105 | -599 | -35.15% | x 1.54 |
|
||||
| lookup_std_highbits | 17,195 | 13,642 | -3,553 | -20.66% | x 1.26 |
|
||||
| lookup_std_random | 17,181 | 13,773 | -3,408 | -19.84% | x 1.25 |
|
||||
| lookup_std_serial | 15,483 | 13,651 | -1,832 | -11.83% | x 1.13 |
|
||||
| lookup_fail_std_highbits | 20,926 | 13,474 | -7,452 | -35.61% | x 1.55 |
|
||||
| lookup_fail_std_random | 21,766 | 13,505 | -8,261 | -37.95% | x 1.61 |
|
||||
| lookup_fail_std_serial | 19,336 | 13,519 | -5,817 | -30.08% | x 1.43 |
|
||||
|
||||
## Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
hashbrown = "0.14"
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```rust
|
||||
use hashbrown::HashMap;
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert(1, "one");
|
||||
```
|
||||
## Flags
|
||||
This crate has the following Cargo features:
|
||||
|
||||
- `nightly`: Enables nightly-only features including: `#[may_dangle]`.
|
||||
- `serde`: Enables serde serialization support.
|
||||
- `rkyv`: Enables rkyv serialization support.
|
||||
- `rayon`: Enables rayon parallel iterator support.
|
||||
- `raw`: Enables access to the experimental and unsafe `RawTable` API.
|
||||
- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost
|
||||
of compilation time. (enabled by default)
|
||||
- `ahash`: Compiles with ahash as default hasher. (enabled by default)
|
||||
- `allocator-api2`: Enables support for allocators that support `allocator-api2`. (enabled by default)
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://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.
|
||||
331
third_party/crates/hashbrown-0.14.5/benches/bench.rs
vendored
Normal file
331
third_party/crates/hashbrown-0.14.5/benches/bench.rs
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
// This benchmark suite contains some benchmarks along a set of dimensions:
|
||||
// Hasher: std default (SipHash) and crate default (AHash).
|
||||
// Int key distribution: low bit heavy, top bit heavy, and random.
|
||||
// Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
use hashbrown::hash_map::DefaultHashBuilder;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use std::{
|
||||
collections::hash_map::RandomState,
|
||||
sync::atomic::{self, AtomicUsize},
|
||||
};
|
||||
|
||||
const SIZE: usize = 1000;
|
||||
|
||||
// The default hashmap when using this crate directly.
|
||||
type AHashMap<K, V> = HashMap<K, V, DefaultHashBuilder>;
|
||||
// This uses the hashmap from this crate with the default hasher of the stdlib.
|
||||
type StdHashMap<K, V> = HashMap<K, V, RandomState>;
|
||||
|
||||
// A random key iterator.
|
||||
#[derive(Clone, Copy)]
|
||||
struct RandomKeys {
|
||||
state: usize,
|
||||
}
|
||||
|
||||
impl RandomKeys {
|
||||
fn new() -> Self {
|
||||
RandomKeys { state: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for RandomKeys {
|
||||
type Item = usize;
|
||||
fn next(&mut self) -> Option<usize> {
|
||||
// Add 1 then multiply by some 32 bit prime.
|
||||
self.state = self.state.wrapping_add(1).wrapping_mul(3_787_392_781);
|
||||
Some(self.state)
|
||||
}
|
||||
}
|
||||
|
||||
// Just an arbitrary side effect to make the maps not shortcircuit to the non-dropping path
|
||||
// when dropping maps/entries (most real world usages likely have drop in the key or value)
|
||||
lazy_static::lazy_static! {
|
||||
static ref SIDE_EFFECT: AtomicUsize = AtomicUsize::new(0);
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct DropType(usize);
|
||||
impl Drop for DropType {
|
||||
fn drop(&mut self) {
|
||||
SIDE_EFFECT.fetch_add(self.0, atomic::Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! bench_suite {
|
||||
($bench_macro:ident, $bench_ahash_serial:ident, $bench_std_serial:ident,
|
||||
$bench_ahash_highbits:ident, $bench_std_highbits:ident,
|
||||
$bench_ahash_random:ident, $bench_std_random:ident) => {
|
||||
$bench_macro!($bench_ahash_serial, AHashMap, 0..);
|
||||
$bench_macro!($bench_std_serial, StdHashMap, 0..);
|
||||
$bench_macro!(
|
||||
$bench_ahash_highbits,
|
||||
AHashMap,
|
||||
(0..).map(usize::swap_bytes)
|
||||
);
|
||||
$bench_macro!(
|
||||
$bench_std_highbits,
|
||||
StdHashMap,
|
||||
(0..).map(usize::swap_bytes)
|
||||
);
|
||||
$bench_macro!($bench_ahash_random, AHashMap, RandomKeys::new());
|
||||
$bench_macro!($bench_std_random, StdHashMap, RandomKeys::new());
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! bench_insert {
|
||||
($name:ident, $maptype:ident, $keydist:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default());
|
||||
b.iter(|| {
|
||||
m.clear();
|
||||
for i in ($keydist).take(SIZE) {
|
||||
m.insert(i, (DropType(i), [i; 20]));
|
||||
}
|
||||
black_box(&mut m);
|
||||
});
|
||||
eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bench_suite!(
|
||||
bench_insert,
|
||||
insert_ahash_serial,
|
||||
insert_std_serial,
|
||||
insert_ahash_highbits,
|
||||
insert_std_highbits,
|
||||
insert_ahash_random,
|
||||
insert_std_random
|
||||
);
|
||||
|
||||
macro_rules! bench_grow_insert {
|
||||
($name:ident, $maptype:ident, $keydist:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut m = $maptype::default();
|
||||
for i in ($keydist).take(SIZE) {
|
||||
m.insert(i, DropType(i));
|
||||
}
|
||||
black_box(&mut m);
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bench_suite!(
|
||||
bench_grow_insert,
|
||||
grow_insert_ahash_serial,
|
||||
grow_insert_std_serial,
|
||||
grow_insert_ahash_highbits,
|
||||
grow_insert_std_highbits,
|
||||
grow_insert_ahash_random,
|
||||
grow_insert_std_random
|
||||
);
|
||||
|
||||
macro_rules! bench_insert_erase {
|
||||
($name:ident, $maptype:ident, $keydist:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut base = $maptype::default();
|
||||
for i in ($keydist).take(SIZE) {
|
||||
base.insert(i, DropType(i));
|
||||
}
|
||||
let skip = $keydist.skip(SIZE);
|
||||
b.iter(|| {
|
||||
let mut m = base.clone();
|
||||
let mut add_iter = skip.clone();
|
||||
let mut remove_iter = $keydist;
|
||||
// While keeping the size constant,
|
||||
// replace the first keydist with the second.
|
||||
for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) {
|
||||
m.insert(add, DropType(add));
|
||||
black_box(m.remove(&remove));
|
||||
}
|
||||
black_box(m);
|
||||
});
|
||||
eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bench_suite!(
|
||||
bench_insert_erase,
|
||||
insert_erase_ahash_serial,
|
||||
insert_erase_std_serial,
|
||||
insert_erase_ahash_highbits,
|
||||
insert_erase_std_highbits,
|
||||
insert_erase_ahash_random,
|
||||
insert_erase_std_random
|
||||
);
|
||||
|
||||
macro_rules! bench_lookup {
|
||||
($name:ident, $maptype:ident, $keydist:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut m = $maptype::default();
|
||||
for i in $keydist.take(SIZE) {
|
||||
m.insert(i, DropType(i));
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
for i in $keydist.take(SIZE) {
|
||||
black_box(m.get(&i));
|
||||
}
|
||||
});
|
||||
eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bench_suite!(
|
||||
bench_lookup,
|
||||
lookup_ahash_serial,
|
||||
lookup_std_serial,
|
||||
lookup_ahash_highbits,
|
||||
lookup_std_highbits,
|
||||
lookup_ahash_random,
|
||||
lookup_std_random
|
||||
);
|
||||
|
||||
macro_rules! bench_lookup_fail {
|
||||
($name:ident, $maptype:ident, $keydist:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut m = $maptype::default();
|
||||
let mut iter = $keydist;
|
||||
for i in (&mut iter).take(SIZE) {
|
||||
m.insert(i, DropType(i));
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
for i in (&mut iter).take(SIZE) {
|
||||
black_box(m.get(&i));
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bench_suite!(
|
||||
bench_lookup_fail,
|
||||
lookup_fail_ahash_serial,
|
||||
lookup_fail_std_serial,
|
||||
lookup_fail_ahash_highbits,
|
||||
lookup_fail_std_highbits,
|
||||
lookup_fail_ahash_random,
|
||||
lookup_fail_std_random
|
||||
);
|
||||
|
||||
macro_rules! bench_iter {
|
||||
($name:ident, $maptype:ident, $keydist:expr) => {
|
||||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut m = $maptype::default();
|
||||
for i in ($keydist).take(SIZE) {
|
||||
m.insert(i, DropType(i));
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
for i in &m {
|
||||
black_box(i);
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bench_suite!(
|
||||
bench_iter,
|
||||
iter_ahash_serial,
|
||||
iter_std_serial,
|
||||
iter_ahash_highbits,
|
||||
iter_std_highbits,
|
||||
iter_ahash_random,
|
||||
iter_std_random
|
||||
);
|
||||
|
||||
#[bench]
|
||||
fn clone_small(b: &mut Bencher) {
|
||||
let mut m = HashMap::new();
|
||||
for i in 0..10 {
|
||||
m.insert(i, DropType(i));
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
black_box(m.clone());
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_from_small(b: &mut Bencher) {
|
||||
let mut m = HashMap::new();
|
||||
let mut m2 = HashMap::new();
|
||||
for i in 0..10 {
|
||||
m.insert(i, DropType(i));
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
m2.clone_from(&m);
|
||||
black_box(&mut m2);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_large(b: &mut Bencher) {
|
||||
let mut m = HashMap::new();
|
||||
for i in 0..1000 {
|
||||
m.insert(i, DropType(i));
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
black_box(m.clone());
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn clone_from_large(b: &mut Bencher) {
|
||||
let mut m = HashMap::new();
|
||||
let mut m2 = HashMap::new();
|
||||
for i in 0..1000 {
|
||||
m.insert(i, DropType(i));
|
||||
}
|
||||
|
||||
b.iter(|| {
|
||||
m2.clone_from(&m);
|
||||
black_box(&mut m2);
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn rehash_in_place(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let mut set = HashSet::new();
|
||||
|
||||
// Each loop triggers one rehash
|
||||
for _ in 0..10 {
|
||||
for i in 0..223 {
|
||||
set.insert(i);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
set.capacity(),
|
||||
224,
|
||||
"The set must be at or close to capacity to trigger a re hashing"
|
||||
);
|
||||
|
||||
for i in 100..1400 {
|
||||
set.remove(&(i - 100));
|
||||
set.insert(i);
|
||||
}
|
||||
set.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
32
third_party/crates/hashbrown-0.14.5/benches/insert_unique_unchecked.rs
vendored
Normal file
32
third_party/crates/hashbrown-0.14.5/benches/insert_unique_unchecked.rs
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
//! Compare `insert` and `insert_unique_unchecked` operations performance.
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn insert(b: &mut Bencher) {
|
||||
let keys: Vec<String> = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect();
|
||||
b.iter(|| {
|
||||
let mut m = HashMap::with_capacity(1000);
|
||||
for k in &keys {
|
||||
m.insert(k, k);
|
||||
}
|
||||
m
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn insert_unique_unchecked(b: &mut Bencher) {
|
||||
let keys: Vec<String> = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect();
|
||||
b.iter(|| {
|
||||
let mut m = HashMap::with_capacity(1000);
|
||||
for k in &keys {
|
||||
m.insert_unique_unchecked(k, k);
|
||||
}
|
||||
m
|
||||
});
|
||||
}
|
||||
1
third_party/crates/hashbrown-0.14.5/clippy.toml
vendored
Normal file
1
third_party/crates/hashbrown-0.14.5/clippy.toml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
doc-valid-idents = [ "CppCon", "SwissTable", "SipHash", "HashDoS" ]
|
||||
6
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/mod.rs
vendored
Normal file
6
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/mod.rs
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#[cfg(feature = "rayon")]
|
||||
pub(crate) mod rayon;
|
||||
#[cfg(feature = "rkyv")]
|
||||
mod rkyv;
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde;
|
||||
27
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs
vendored
Normal file
27
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
use alloc::collections::LinkedList;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
/// Helper for collecting parallel iterators to an intermediary
|
||||
#[allow(clippy::linkedlist)] // yes, we need linked list here for efficient appending!
|
||||
pub(super) fn collect<I: IntoParallelIterator>(iter: I) -> (LinkedList<Vec<I::Item>>, usize) {
|
||||
let list = iter
|
||||
.into_par_iter()
|
||||
.fold(Vec::new, |mut vec, elem| {
|
||||
vec.push(elem);
|
||||
vec
|
||||
})
|
||||
.map(|vec| {
|
||||
let mut list = LinkedList::new();
|
||||
list.push_back(vec);
|
||||
list
|
||||
})
|
||||
.reduce(LinkedList::new, |mut list1, mut list2| {
|
||||
list1.append(&mut list2);
|
||||
list1
|
||||
});
|
||||
|
||||
let len = list.iter().map(Vec::len).sum();
|
||||
(list, len)
|
||||
}
|
||||
721
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs
vendored
Normal file
721
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs
vendored
Normal file
@@ -0,0 +1,721 @@
|
||||
//! Rayon extensions for `HashMap`.
|
||||
|
||||
use super::raw::{RawIntoParIter, RawParDrain, RawParIter};
|
||||
use crate::hash_map::HashMap;
|
||||
use crate::raw::{Allocator, Global};
|
||||
use core::fmt;
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use core::marker::PhantomData;
|
||||
use rayon::iter::plumbing::UnindexedConsumer;
|
||||
use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator};
|
||||
|
||||
/// Parallel iterator over shared references to entries in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter`] method on [`HashMap`]
|
||||
/// (provided by the [`IntoParallelRefIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html
|
||||
pub struct ParIter<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe {
|
||||
let r = x.as_ref();
|
||||
(&r.0, &r.1)
|
||||
})
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Clone for ParIter<'_, K, V> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug> fmt::Debug for ParIter<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let iter = unsafe { self.inner.iter() }.map(|x| unsafe {
|
||||
let r = x.as_ref();
|
||||
(&r.0, &r.1)
|
||||
});
|
||||
f.debug_list().entries(iter).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to keys in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_keys`] method on [`HashMap`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_keys`]: /hashbrown/struct.HashMap.html#method.par_keys
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
pub struct ParKeys<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> {
|
||||
type Item = &'a K;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { &x.as_ref().0 })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Clone for ParKeys<'_, K, V> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V> fmt::Debug for ParKeys<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().0 });
|
||||
f.debug_list().entries(iter).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to values in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_values`] method on [`HashMap`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
pub struct ParValues<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> {
|
||||
type Item = &'a V;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { &x.as_ref().1 })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Clone for ParValues<'_, K, V> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V: fmt::Debug> fmt::Debug for ParValues<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().1 });
|
||||
f.debug_list().entries(iter).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over mutable references to entries in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter_mut`] method on [`HashMap`]
|
||||
/// (provided by the [`IntoParallelRefMutIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html
|
||||
pub struct ParIterMut<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a mut V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe {
|
||||
let r = x.as_mut();
|
||||
(&r.0, &mut r.1)
|
||||
})
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug> fmt::Debug for ParIterMut<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over mutable references to values in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_values_mut`] method on [`HashMap`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_values_mut`]: /hashbrown/struct.HashMap.html#method.par_values_mut
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
pub struct ParValuesMut<'a, K, V> {
|
||||
inner: RawParIter<(K, V)>,
|
||||
marker: PhantomData<(&'a K, &'a mut V)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> {
|
||||
type Item = &'a mut V;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { &mut x.as_mut().1 })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V: fmt::Debug> fmt::Debug for ParValuesMut<'_, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParValues {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over entries of a consumed map.
|
||||
///
|
||||
/// This iterator is created by the [`into_par_iter`] method on [`HashMap`]
|
||||
/// (provided by the [`IntoParallelIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html
|
||||
pub struct IntoParIter<K, V, A: Allocator = Global> {
|
||||
inner: RawIntoParIter<(K, V), A>,
|
||||
}
|
||||
|
||||
impl<K: Send, V: Send, A: Allocator + Send> ParallelIterator for IntoParIter<K, V, A> {
|
||||
type Item = (K, V);
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug, A: Allocator> fmt::Debug for IntoParIter<K, V, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: unsafe { self.inner.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel draining iterator over entries of a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_drain`] method on [`HashMap`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain
|
||||
/// [`HashMap`]: /hashbrown/struct.HashMap.html
|
||||
pub struct ParDrain<'a, K, V, A: Allocator = Global> {
|
||||
inner: RawParDrain<'a, (K, V), A>,
|
||||
}
|
||||
|
||||
impl<K: Send, V: Send, A: Allocator + Sync> ParallelIterator for ParDrain<'_, K, V, A> {
|
||||
type Item = (K, V);
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug, A: Allocator> fmt::Debug for ParDrain<'_, K, V, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: unsafe { self.inner.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Sync, V: Sync, S, A: Allocator> HashMap<K, V, S, A> {
|
||||
/// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_keys(&self) -> ParKeys<'_, K, V> {
|
||||
ParKeys {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Visits (potentially in parallel) immutably borrowed values in an arbitrary order.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_values(&self) -> ParValues<'_, K, V> {
|
||||
ParValues {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Send, V: Send, S, A: Allocator> HashMap<K, V, S, A> {
|
||||
/// Visits (potentially in parallel) mutably borrowed values in an arbitrary order.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> {
|
||||
ParValuesMut {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes (potentially in parallel) all values in an arbitrary order,
|
||||
/// while preserving the map's allocated memory for reuse.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> {
|
||||
ParDrain {
|
||||
inner: self.table.par_drain(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S, A> HashMap<K, V, S, A>
|
||||
where
|
||||
K: Eq + Hash + Sync,
|
||||
V: PartialEq + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
/// Returns `true` if the map is equal to another,
|
||||
/// i.e. both maps contain the same keys mapped to the same values.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_eq(&self, other: &Self) -> bool {
|
||||
self.len() == other.len()
|
||||
&& self
|
||||
.into_par_iter()
|
||||
.all(|(key, value)| other.get(key).map_or(false, |v| *value == *v))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Send, V: Send, S, A: Allocator + Send> IntoParallelIterator for HashMap<K, V, S, A> {
|
||||
type Item = (K, V);
|
||||
type Iter = IntoParIter<K, V, A>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
IntoParIter {
|
||||
inner: self.table.into_par_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap<K, V, S, A> {
|
||||
type Item = (&'a K, &'a V);
|
||||
type Iter = ParIter<'a, K, V>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIter {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut HashMap<K, V, S, A> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
type Iter = ParIterMut<'a, K, V>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIterMut {
|
||||
inner: unsafe { self.table.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect (key, value) pairs from a parallel iterator into a
|
||||
/// hashmap. If multiple pairs correspond to the same key, then the
|
||||
/// ones produced earlier in the parallel iterator will be
|
||||
/// overwritten, just as with a sequential iterator.
|
||||
impl<K, V, S> FromParallelIterator<(K, V)> for HashMap<K, V, S, Global>
|
||||
where
|
||||
K: Eq + Hash + Send,
|
||||
V: Send,
|
||||
S: BuildHasher + Default,
|
||||
{
|
||||
fn from_par_iter<P>(par_iter: P) -> Self
|
||||
where
|
||||
P: IntoParallelIterator<Item = (K, V)>,
|
||||
{
|
||||
let mut map = HashMap::default();
|
||||
map.par_extend(par_iter);
|
||||
map
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a hash map with items from a parallel iterator.
|
||||
impl<K, V, S, A> ParallelExtend<(K, V)> for HashMap<K, V, S, A>
|
||||
where
|
||||
K: Eq + Hash + Send,
|
||||
V: Send,
|
||||
S: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
fn par_extend<I>(&mut self, par_iter: I)
|
||||
where
|
||||
I: IntoParallelIterator<Item = (K, V)>,
|
||||
{
|
||||
extend(self, par_iter);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a hash map with copied items from a parallel iterator.
|
||||
impl<'a, K, V, S, A> ParallelExtend<(&'a K, &'a V)> for HashMap<K, V, S, A>
|
||||
where
|
||||
K: Copy + Eq + Hash + Sync,
|
||||
V: Copy + Sync,
|
||||
S: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
fn par_extend<I>(&mut self, par_iter: I)
|
||||
where
|
||||
I: IntoParallelIterator<Item = (&'a K, &'a V)>,
|
||||
{
|
||||
extend(self, par_iter);
|
||||
}
|
||||
}
|
||||
|
||||
// This is equal to the normal `HashMap` -- no custom advantage.
|
||||
fn extend<K, V, S, A, I>(map: &mut HashMap<K, V, S, A>, par_iter: I)
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
I: IntoParallelIterator,
|
||||
A: Allocator,
|
||||
HashMap<K, V, S, A>: Extend<I::Item>,
|
||||
{
|
||||
let (list, len) = super::helpers::collect(par_iter);
|
||||
|
||||
// Keys may be already present or show multiple times in the iterator.
|
||||
// Reserve the entire length if the map is empty.
|
||||
// Otherwise reserve half the length (rounded up), so the map
|
||||
// will only resize twice in the worst case.
|
||||
let reserve = if map.is_empty() { len } else { (len + 1) / 2 };
|
||||
map.reserve(reserve);
|
||||
for vec in list {
|
||||
map.extend(vec);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_par_map {
|
||||
use alloc::vec::Vec;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::hash_map::HashMap;
|
||||
|
||||
struct Dropable<'a> {
|
||||
k: usize,
|
||||
counter: &'a AtomicUsize,
|
||||
}
|
||||
|
||||
impl Dropable<'_> {
|
||||
fn new(k: usize, counter: &AtomicUsize) -> Dropable<'_> {
|
||||
counter.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
Dropable { k, counter }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Dropable<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.counter.fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Dropable<'_> {
|
||||
fn clone(&self) -> Self {
|
||||
Dropable::new(self.k, self.counter)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Dropable<'_> {
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
self.k.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Dropable<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.k == other.k
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Dropable<'_> {}
|
||||
|
||||
#[test]
|
||||
fn test_into_iter_drops() {
|
||||
let key = AtomicUsize::new(0);
|
||||
let value = AtomicUsize::new(0);
|
||||
|
||||
let hm = {
|
||||
let mut hm = HashMap::new();
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 0);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 0);
|
||||
|
||||
for i in 0..100 {
|
||||
let d1 = Dropable::new(i, &key);
|
||||
let d2 = Dropable::new(i + 100, &value);
|
||||
hm.insert(d1, d2);
|
||||
}
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
hm
|
||||
};
|
||||
|
||||
// By the way, ensure that cloning doesn't screw up the dropping.
|
||||
drop(hm.clone());
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
// Ensure that dropping the iterator does not leak anything.
|
||||
drop(hm.clone().into_par_iter());
|
||||
|
||||
{
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
// retain only half
|
||||
let _v: Vec<_> = hm.into_par_iter().filter(|(key, _)| key.k < 50).collect();
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 50);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 50);
|
||||
};
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 0);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drain_drops() {
|
||||
let key = AtomicUsize::new(0);
|
||||
let value = AtomicUsize::new(0);
|
||||
|
||||
let mut hm = {
|
||||
let mut hm = HashMap::new();
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 0);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 0);
|
||||
|
||||
for i in 0..100 {
|
||||
let d1 = Dropable::new(i, &key);
|
||||
let d2 = Dropable::new(i + 100, &value);
|
||||
hm.insert(d1, d2);
|
||||
}
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
hm
|
||||
};
|
||||
|
||||
// By the way, ensure that cloning doesn't screw up the dropping.
|
||||
drop(hm.clone());
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
// Ensure that dropping the drain iterator does not leak anything.
|
||||
drop(hm.clone().par_drain());
|
||||
|
||||
{
|
||||
assert_eq!(key.load(Ordering::Relaxed), 100);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 100);
|
||||
|
||||
// retain only half
|
||||
let _v: Vec<_> = hm.drain().filter(|(key, _)| key.k < 50).collect();
|
||||
assert!(hm.is_empty());
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 50);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 50);
|
||||
};
|
||||
|
||||
assert_eq!(key.load(Ordering::Relaxed), 0);
|
||||
assert_eq!(value.load(Ordering::Relaxed), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_iter() {
|
||||
let mut m: HashMap<isize, bool> = HashMap::new();
|
||||
assert_eq!(m.par_drain().count(), 0);
|
||||
assert_eq!(m.par_keys().count(), 0);
|
||||
assert_eq!(m.par_values().count(), 0);
|
||||
assert_eq!(m.par_values_mut().count(), 0);
|
||||
assert_eq!(m.par_iter().count(), 0);
|
||||
assert_eq!(m.par_iter_mut().count(), 0);
|
||||
assert_eq!(m.len(), 0);
|
||||
assert!(m.is_empty());
|
||||
assert_eq!(m.into_par_iter().count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate() {
|
||||
let mut m = HashMap::with_capacity(4);
|
||||
for i in 0..32 {
|
||||
assert!(m.insert(i, i * 2).is_none());
|
||||
}
|
||||
assert_eq!(m.len(), 32);
|
||||
|
||||
let observed = AtomicUsize::new(0);
|
||||
|
||||
m.par_iter().for_each(|(k, v)| {
|
||||
assert_eq!(*v, *k * 2);
|
||||
observed.fetch_or(1 << *k, Ordering::Relaxed);
|
||||
});
|
||||
assert_eq!(observed.into_inner(), 0xFFFF_FFFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys() {
|
||||
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
|
||||
let map: HashMap<_, _> = vec.into_par_iter().collect();
|
||||
let keys: Vec<_> = map.par_keys().cloned().collect();
|
||||
assert_eq!(keys.len(), 3);
|
||||
assert!(keys.contains(&1));
|
||||
assert!(keys.contains(&2));
|
||||
assert!(keys.contains(&3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_values() {
|
||||
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
|
||||
let map: HashMap<_, _> = vec.into_par_iter().collect();
|
||||
let values: Vec<_> = map.par_values().cloned().collect();
|
||||
assert_eq!(values.len(), 3);
|
||||
assert!(values.contains(&'a'));
|
||||
assert!(values.contains(&'b'));
|
||||
assert!(values.contains(&'c'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_values_mut() {
|
||||
let vec = vec![(1, 1), (2, 2), (3, 3)];
|
||||
let mut map: HashMap<_, _> = vec.into_par_iter().collect();
|
||||
map.par_values_mut().for_each(|value| *value *= 2);
|
||||
let values: Vec<_> = map.par_values().cloned().collect();
|
||||
assert_eq!(values.len(), 3);
|
||||
assert!(values.contains(&2));
|
||||
assert!(values.contains(&4));
|
||||
assert!(values.contains(&6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq() {
|
||||
let mut m1 = HashMap::new();
|
||||
m1.insert(1, 2);
|
||||
m1.insert(2, 3);
|
||||
m1.insert(3, 4);
|
||||
|
||||
let mut m2 = HashMap::new();
|
||||
m2.insert(1, 2);
|
||||
m2.insert(2, 3);
|
||||
|
||||
assert!(!m1.par_eq(&m2));
|
||||
|
||||
m2.insert(3, 4);
|
||||
|
||||
assert!(m1.par_eq(&m2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
||||
|
||||
let map: HashMap<_, _> = xs.par_iter().cloned().collect();
|
||||
|
||||
for &(k, v) in &xs {
|
||||
assert_eq!(map.get(&k), Some(&v));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extend_ref() {
|
||||
let mut a = HashMap::new();
|
||||
a.insert(1, "one");
|
||||
let mut b = HashMap::new();
|
||||
b.insert(2, "two");
|
||||
b.insert(3, "three");
|
||||
|
||||
a.par_extend(&b);
|
||||
|
||||
assert_eq!(a.len(), 3);
|
||||
assert_eq!(a[&1], "one");
|
||||
assert_eq!(a[&2], "two");
|
||||
assert_eq!(a[&3], "three");
|
||||
}
|
||||
}
|
||||
5
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs
vendored
Normal file
5
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
mod helpers;
|
||||
pub(crate) mod map;
|
||||
pub(crate) mod raw;
|
||||
pub(crate) mod set;
|
||||
pub(crate) mod table;
|
||||
230
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs
vendored
Normal file
230
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
use crate::raw::Bucket;
|
||||
use crate::raw::{Allocator, Global, RawIter, RawIterRange, RawTable};
|
||||
use crate::scopeguard::guard;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::ptr::NonNull;
|
||||
use rayon::iter::{
|
||||
plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer},
|
||||
ParallelIterator,
|
||||
};
|
||||
|
||||
/// Parallel iterator which returns a raw pointer to every full bucket in the table.
|
||||
pub struct RawParIter<T> {
|
||||
iter: RawIterRange<T>,
|
||||
}
|
||||
|
||||
impl<T> RawParIter<T> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub(super) unsafe fn iter(&self) -> RawIterRange<T> {
|
||||
self.iter.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for RawParIter<T> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
iter: self.iter.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<RawIter<T>> for RawParIter<T> {
|
||||
fn from(it: RawIter<T>) -> Self {
|
||||
RawParIter { iter: it.iter }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ParallelIterator for RawParIter<T> {
|
||||
type Item = Bucket<T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
let producer = ParIterProducer { iter: self.iter };
|
||||
plumbing::bridge_unindexed(producer, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Producer which returns a `Bucket<T>` for every element.
|
||||
struct ParIterProducer<T> {
|
||||
iter: RawIterRange<T>,
|
||||
}
|
||||
|
||||
impl<T> UnindexedProducer for ParIterProducer<T> {
|
||||
type Item = Bucket<T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn split(self) -> (Self, Option<Self>) {
|
||||
let (left, right) = self.iter.split();
|
||||
let left = ParIterProducer { iter: left };
|
||||
let right = right.map(|right| ParIterProducer { iter: right });
|
||||
(left, right)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn fold_with<F>(self, folder: F) -> F
|
||||
where
|
||||
F: Folder<Self::Item>,
|
||||
{
|
||||
folder.consume_iter(self.iter)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator which consumes a table and returns elements.
|
||||
pub struct RawIntoParIter<T, A: Allocator = Global> {
|
||||
table: RawTable<T, A>,
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> RawIntoParIter<T, A> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub(super) unsafe fn par_iter(&self) -> RawParIter<T> {
|
||||
self.table.par_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send> ParallelIterator for RawIntoParIter<T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
let iter = unsafe { self.table.iter().iter };
|
||||
let _guard = guard(self.table.into_allocation(), |alloc| {
|
||||
if let Some((ptr, layout, ref alloc)) = *alloc {
|
||||
unsafe {
|
||||
alloc.deallocate(ptr, layout);
|
||||
}
|
||||
}
|
||||
});
|
||||
let producer = ParDrainProducer { iter };
|
||||
plumbing::bridge_unindexed(producer, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator which consumes elements without freeing the table storage.
|
||||
pub struct RawParDrain<'a, T, A: Allocator = Global> {
|
||||
// We don't use a &'a mut RawTable<T> because we want RawParDrain to be
|
||||
// covariant over T.
|
||||
table: NonNull<RawTable<T, A>>,
|
||||
marker: PhantomData<&'a RawTable<T, A>>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Send, A: Allocator> Send for RawParDrain<'_, T, A> {}
|
||||
|
||||
impl<T, A: Allocator> RawParDrain<'_, T, A> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub(super) unsafe fn par_iter(&self) -> RawParIter<T> {
|
||||
self.table.as_ref().par_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator> ParallelIterator for RawParDrain<'_, T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
let _guard = guard(self.table, |table| unsafe {
|
||||
table.as_mut().clear_no_drop();
|
||||
});
|
||||
let iter = unsafe { self.table.as_ref().iter().iter };
|
||||
mem::forget(self);
|
||||
let producer = ParDrainProducer { iter };
|
||||
plumbing::bridge_unindexed(producer, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> Drop for RawParDrain<'_, T, A> {
|
||||
fn drop(&mut self) {
|
||||
// If drive_unindexed is not called then simply clear the table.
|
||||
unsafe {
|
||||
self.table.as_mut().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Producer which will consume all elements in the range, even if it is dropped
|
||||
/// halfway through.
|
||||
struct ParDrainProducer<T> {
|
||||
iter: RawIterRange<T>,
|
||||
}
|
||||
|
||||
impl<T: Send> UnindexedProducer for ParDrainProducer<T> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn split(self) -> (Self, Option<Self>) {
|
||||
let (left, right) = self.iter.clone().split();
|
||||
mem::forget(self);
|
||||
let left = ParDrainProducer { iter: left };
|
||||
let right = right.map(|right| ParDrainProducer { iter: right });
|
||||
(left, right)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn fold_with<F>(mut self, mut folder: F) -> F
|
||||
where
|
||||
F: Folder<Self::Item>,
|
||||
{
|
||||
// Make sure to modify the iterator in-place so that any remaining
|
||||
// elements are processed in our Drop impl.
|
||||
for item in &mut self.iter {
|
||||
folder = folder.consume(unsafe { item.read() });
|
||||
if folder.full() {
|
||||
return folder;
|
||||
}
|
||||
}
|
||||
|
||||
// If we processed all elements then we don't need to run the drop.
|
||||
mem::forget(self);
|
||||
folder
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for ParDrainProducer<T> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drop(&mut self) {
|
||||
// Drop all remaining elements
|
||||
if mem::needs_drop::<T>() {
|
||||
for item in &mut self.iter {
|
||||
unsafe {
|
||||
item.drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> RawTable<T, A> {
|
||||
/// Returns a parallel iterator over the elements in a `RawTable`.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub unsafe fn par_iter(&self) -> RawParIter<T> {
|
||||
RawParIter {
|
||||
iter: self.iter().iter,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a parallel iterator over the elements in a `RawTable`.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn into_par_iter(self) -> RawIntoParIter<T, A> {
|
||||
RawIntoParIter { table: self }
|
||||
}
|
||||
|
||||
/// Returns a parallel iterator which consumes all elements of a `RawTable`
|
||||
/// without freeing its memory allocation.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_drain(&mut self) -> RawParDrain<'_, T, A> {
|
||||
RawParDrain {
|
||||
table: NonNull::from(self),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
659
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs
vendored
Normal file
659
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs
vendored
Normal file
@@ -0,0 +1,659 @@
|
||||
//! Rayon extensions for `HashSet`.
|
||||
|
||||
use super::map;
|
||||
use crate::hash_set::HashSet;
|
||||
use crate::raw::{Allocator, Global};
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use rayon::iter::plumbing::UnindexedConsumer;
|
||||
use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator};
|
||||
|
||||
/// Parallel iterator over elements of a consumed set.
|
||||
///
|
||||
/// This iterator is created by the [`into_par_iter`] method on [`HashSet`]
|
||||
/// (provided by the [`IntoParallelIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`into_par_iter`]: /hashbrown/struct.HashSet.html#method.into_par_iter
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html
|
||||
pub struct IntoParIter<T, A: Allocator = Global> {
|
||||
inner: map::IntoParIter<T, (), A>,
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send> ParallelIterator for IntoParIter<T, A> {
|
||||
type Item = T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.map(|(k, _)| k).drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel draining iterator over entries of a set.
|
||||
///
|
||||
/// This iterator is created by the [`par_drain`] method on [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_drain`]: /hashbrown/struct.HashSet.html#method.par_drain
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParDrain<'a, T, A: Allocator = Global> {
|
||||
inner: map::ParDrain<'a, T, (), A>,
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send + Sync> ParallelIterator for ParDrain<'_, T, A> {
|
||||
type Item = T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.map(|(k, _)| k).drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in a set.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter`] method on [`HashSet`]
|
||||
/// (provided by the [`IntoParallelRefIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter`]: /hashbrown/struct.HashSet.html#method.par_iter
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html
|
||||
pub struct ParIter<'a, T> {
|
||||
inner: map::ParKeys<'a, T, ()>,
|
||||
}
|
||||
|
||||
impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in the difference of
|
||||
/// sets.
|
||||
///
|
||||
/// This iterator is created by the [`par_difference`] method on [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_difference`]: /hashbrown/struct.HashSet.html#method.par_difference
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParDifference<'a, T, S, A: Allocator = Global> {
|
||||
a: &'a HashSet<T, S, A>,
|
||||
b: &'a HashSet<T, S, A>,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> ParallelIterator for ParDifference<'a, T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.a
|
||||
.into_par_iter()
|
||||
.filter(|&x| !self.b.contains(x))
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in the symmetric
|
||||
/// difference of sets.
|
||||
///
|
||||
/// This iterator is created by the [`par_symmetric_difference`] method on
|
||||
/// [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_symmetric_difference`]: /hashbrown/struct.HashSet.html#method.par_symmetric_difference
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParSymmetricDifference<'a, T, S, A: Allocator = Global> {
|
||||
a: &'a HashSet<T, S, A>,
|
||||
b: &'a HashSet<T, S, A>,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> ParallelIterator for ParSymmetricDifference<'a, T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.a
|
||||
.par_difference(self.b)
|
||||
.chain(self.b.par_difference(self.a))
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in the intersection of
|
||||
/// sets.
|
||||
///
|
||||
/// This iterator is created by the [`par_intersection`] method on [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_intersection`]: /hashbrown/struct.HashSet.html#method.par_intersection
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParIntersection<'a, T, S, A: Allocator = Global> {
|
||||
a: &'a HashSet<T, S, A>,
|
||||
b: &'a HashSet<T, S, A>,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> ParallelIterator for ParIntersection<'a, T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.a
|
||||
.into_par_iter()
|
||||
.filter(|&x| self.b.contains(x))
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over shared references to elements in the union of sets.
|
||||
///
|
||||
/// This iterator is created by the [`par_union`] method on [`HashSet`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union
|
||||
/// [`HashSet`]: /hashbrown/struct.HashSet.html
|
||||
pub struct ParUnion<'a, T, S, A: Allocator = Global> {
|
||||
a: &'a HashSet<T, S, A>,
|
||||
b: &'a HashSet<T, S, A>,
|
||||
}
|
||||
|
||||
impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
// We'll iterate one set in full, and only the remaining difference from the other.
|
||||
// Use the smaller set for the difference in order to reduce hash lookups.
|
||||
let (smaller, larger) = if self.a.len() <= self.b.len() {
|
||||
(self.a, self.b)
|
||||
} else {
|
||||
(self.b, self.a)
|
||||
};
|
||||
larger
|
||||
.into_par_iter()
|
||||
.chain(smaller.par_difference(larger))
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, A> HashSet<T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Sync,
|
||||
S: BuildHasher + Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
/// Visits (potentially in parallel) the values representing the union,
|
||||
/// i.e. all the values in `self` or `other`, without duplicates.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S, A> {
|
||||
ParUnion { a: self, b: other }
|
||||
}
|
||||
|
||||
/// Visits (potentially in parallel) the values representing the difference,
|
||||
/// i.e. the values that are in `self` but not in `other`.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_difference<'a>(&'a self, other: &'a Self) -> ParDifference<'a, T, S, A> {
|
||||
ParDifference { a: self, b: other }
|
||||
}
|
||||
|
||||
/// Visits (potentially in parallel) the values representing the symmetric
|
||||
/// difference, i.e. the values that are in `self` or in `other` but not in both.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_symmetric_difference<'a>(
|
||||
&'a self,
|
||||
other: &'a Self,
|
||||
) -> ParSymmetricDifference<'a, T, S, A> {
|
||||
ParSymmetricDifference { a: self, b: other }
|
||||
}
|
||||
|
||||
/// Visits (potentially in parallel) the values representing the
|
||||
/// intersection, i.e. the values that are both in `self` and `other`.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_intersection<'a>(&'a self, other: &'a Self) -> ParIntersection<'a, T, S, A> {
|
||||
ParIntersection { a: self, b: other }
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` has no elements in common with `other`.
|
||||
/// This is equivalent to checking for an empty intersection.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_is_disjoint(&self, other: &Self) -> bool {
|
||||
self.into_par_iter().all(|x| !other.contains(x))
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a subset of another,
|
||||
/// i.e. `other` contains at least all the values in `self`.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_is_subset(&self, other: &Self) -> bool {
|
||||
if self.len() <= other.len() {
|
||||
self.into_par_iter().all(|x| other.contains(x))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a superset of another,
|
||||
/// i.e. `self` contains at least all the values in `other`.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_is_superset(&self, other: &Self) -> bool {
|
||||
other.par_is_subset(self)
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is equal to another,
|
||||
/// i.e. both sets contain the same values.
|
||||
///
|
||||
/// This method runs in a potentially parallel fashion.
|
||||
pub fn par_eq(&self, other: &Self) -> bool {
|
||||
self.len() == other.len() && self.par_is_subset(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, A> HashSet<T, S, A>
|
||||
where
|
||||
T: Eq + Hash + Send,
|
||||
A: Allocator + Send,
|
||||
{
|
||||
/// Consumes (potentially in parallel) all values in an arbitrary order,
|
||||
/// while preserving the set's allocated memory for reuse.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_drain(&mut self) -> ParDrain<'_, T, A> {
|
||||
ParDrain {
|
||||
inner: self.map.par_drain(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, S, A: Allocator + Send> IntoParallelIterator for HashSet<T, S, A> {
|
||||
type Item = T;
|
||||
type Iter = IntoParIter<T, A>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
IntoParIter {
|
||||
inner: self.map.into_par_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Sync, S, A: Allocator> IntoParallelIterator for &'a HashSet<T, S, A> {
|
||||
type Item = &'a T;
|
||||
type Iter = ParIter<'a, T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIter {
|
||||
inner: self.map.par_keys(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect values from a parallel iterator into a hashset.
|
||||
impl<T, S> FromParallelIterator<T> for HashSet<T, S, Global>
|
||||
where
|
||||
T: Eq + Hash + Send,
|
||||
S: BuildHasher + Default,
|
||||
{
|
||||
fn from_par_iter<P>(par_iter: P) -> Self
|
||||
where
|
||||
P: IntoParallelIterator<Item = T>,
|
||||
{
|
||||
let mut set = HashSet::default();
|
||||
set.par_extend(par_iter);
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a hash set with items from a parallel iterator.
|
||||
impl<T, S> ParallelExtend<T> for HashSet<T, S, Global>
|
||||
where
|
||||
T: Eq + Hash + Send,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn par_extend<I>(&mut self, par_iter: I)
|
||||
where
|
||||
I: IntoParallelIterator<Item = T>,
|
||||
{
|
||||
extend(self, par_iter);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a hash set with copied items from a parallel iterator.
|
||||
impl<'a, T, S> ParallelExtend<&'a T> for HashSet<T, S, Global>
|
||||
where
|
||||
T: 'a + Copy + Eq + Hash + Sync,
|
||||
S: BuildHasher,
|
||||
{
|
||||
fn par_extend<I>(&mut self, par_iter: I)
|
||||
where
|
||||
I: IntoParallelIterator<Item = &'a T>,
|
||||
{
|
||||
extend(self, par_iter);
|
||||
}
|
||||
}
|
||||
|
||||
// This is equal to the normal `HashSet` -- no custom advantage.
|
||||
fn extend<T, S, I, A>(set: &mut HashSet<T, S, A>, par_iter: I)
|
||||
where
|
||||
T: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
A: Allocator,
|
||||
I: IntoParallelIterator,
|
||||
HashSet<T, S, A>: Extend<I::Item>,
|
||||
{
|
||||
let (list, len) = super::helpers::collect(par_iter);
|
||||
|
||||
// Values may be already present or show multiple times in the iterator.
|
||||
// Reserve the entire length if the set is empty.
|
||||
// Otherwise reserve half the length (rounded up), so the set
|
||||
// will only resize twice in the worst case.
|
||||
let reserve = if set.is_empty() { len } else { (len + 1) / 2 };
|
||||
set.reserve(reserve);
|
||||
for vec in list {
|
||||
set.extend(vec);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_par_set {
|
||||
use alloc::vec::Vec;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::hash_set::HashSet;
|
||||
|
||||
#[test]
|
||||
fn test_disjoint() {
|
||||
let mut xs = HashSet::new();
|
||||
let mut ys = HashSet::new();
|
||||
assert!(xs.par_is_disjoint(&ys));
|
||||
assert!(ys.par_is_disjoint(&xs));
|
||||
assert!(xs.insert(5));
|
||||
assert!(ys.insert(11));
|
||||
assert!(xs.par_is_disjoint(&ys));
|
||||
assert!(ys.par_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.par_is_disjoint(&ys));
|
||||
assert!(ys.par_is_disjoint(&xs));
|
||||
assert!(ys.insert(7));
|
||||
assert!(!xs.par_is_disjoint(&ys));
|
||||
assert!(!ys.par_is_disjoint(&xs));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subset_and_superset() {
|
||||
let mut a = HashSet::new();
|
||||
assert!(a.insert(0));
|
||||
assert!(a.insert(5));
|
||||
assert!(a.insert(11));
|
||||
assert!(a.insert(7));
|
||||
|
||||
let mut b = HashSet::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.par_is_subset(&b));
|
||||
assert!(!a.par_is_superset(&b));
|
||||
assert!(!b.par_is_subset(&a));
|
||||
assert!(!b.par_is_superset(&a));
|
||||
|
||||
assert!(b.insert(5));
|
||||
|
||||
assert!(a.par_is_subset(&b));
|
||||
assert!(!a.par_is_superset(&b));
|
||||
assert!(!b.par_is_subset(&a));
|
||||
assert!(b.par_is_superset(&a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate() {
|
||||
let mut a = HashSet::new();
|
||||
for i in 0..32 {
|
||||
assert!(a.insert(i));
|
||||
}
|
||||
let observed = AtomicUsize::new(0);
|
||||
a.par_iter().for_each(|k| {
|
||||
observed.fetch_or(1 << *k, Ordering::Relaxed);
|
||||
});
|
||||
assert_eq!(observed.into_inner(), 0xFFFF_FFFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intersection() {
|
||||
let mut a = HashSet::new();
|
||||
let mut b = HashSet::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 expected = [3, 5, 11, 77];
|
||||
let i = a
|
||||
.par_intersection(&b)
|
||||
.map(|x| {
|
||||
assert!(expected.contains(x));
|
||||
1
|
||||
})
|
||||
.sum::<usize>();
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_difference() {
|
||||
let mut a = HashSet::new();
|
||||
let mut b = HashSet::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 expected = [1, 5, 11];
|
||||
let i = a
|
||||
.par_difference(&b)
|
||||
.map(|x| {
|
||||
assert!(expected.contains(x));
|
||||
1
|
||||
})
|
||||
.sum::<usize>();
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symmetric_difference() {
|
||||
let mut a = HashSet::new();
|
||||
let mut b = HashSet::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 expected = [-2, 1, 5, 11, 14, 22];
|
||||
let i = a
|
||||
.par_symmetric_difference(&b)
|
||||
.map(|x| {
|
||||
assert!(expected.contains(x));
|
||||
1
|
||||
})
|
||||
.sum::<usize>();
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_union() {
|
||||
let mut a = HashSet::new();
|
||||
let mut b = HashSet::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 expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
|
||||
let i = a
|
||||
.par_union(&b)
|
||||
.map(|x| {
|
||||
assert!(expected.contains(x));
|
||||
1
|
||||
})
|
||||
.sum::<usize>();
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
let set: HashSet<_> = xs.par_iter().cloned().collect();
|
||||
|
||||
for x in &xs {
|
||||
assert!(set.contains(x));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter() {
|
||||
let hs = {
|
||||
let mut hs = HashSet::new();
|
||||
|
||||
hs.insert('a');
|
||||
hs.insert('b');
|
||||
|
||||
hs
|
||||
};
|
||||
|
||||
let v = hs.into_par_iter().collect::<Vec<char>>();
|
||||
assert!(v == ['a', 'b'] || v == ['b', 'a']);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eq() {
|
||||
// These constants once happened to expose a bug in insert().
|
||||
// I'm keeping them around to prevent a regression.
|
||||
let mut s1 = HashSet::new();
|
||||
|
||||
s1.insert(1);
|
||||
s1.insert(2);
|
||||
s1.insert(3);
|
||||
|
||||
let mut s2 = HashSet::new();
|
||||
|
||||
s2.insert(1);
|
||||
s2.insert(2);
|
||||
|
||||
assert!(!s1.par_eq(&s2));
|
||||
|
||||
s2.insert(3);
|
||||
|
||||
assert!(s1.par_eq(&s2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extend_ref() {
|
||||
let mut a = HashSet::new();
|
||||
a.insert(1);
|
||||
|
||||
a.par_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 = HashSet::new();
|
||||
b.insert(5);
|
||||
b.insert(6);
|
||||
|
||||
a.par_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));
|
||||
}
|
||||
}
|
||||
252
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs
vendored
Normal file
252
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
//! Rayon extensions for `HashTable`.
|
||||
|
||||
use super::raw::{RawIntoParIter, RawParDrain, RawParIter};
|
||||
use crate::hash_table::HashTable;
|
||||
use crate::raw::{Allocator, Global};
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
use rayon::iter::plumbing::UnindexedConsumer;
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
/// Parallel iterator over shared references to entries in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter`] method on [`HashTable`]
|
||||
/// (provided by the [`IntoParallelRefIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter`]: /hashbrown/struct.HashTable.html#method.par_iter
|
||||
/// [`HashTable`]: /hashbrown/struct.HashTable.html
|
||||
/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html
|
||||
pub struct ParIter<'a, T> {
|
||||
inner: RawParIter<T>,
|
||||
marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { x.as_ref() })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for ParIter<'_, T> {
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for ParIter<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let iter = unsafe { self.inner.iter() }.map(|x| unsafe { x.as_ref() });
|
||||
f.debug_list().entries(iter).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over mutable references to entries in a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_iter_mut`] method on [`HashTable`]
|
||||
/// (provided by the [`IntoParallelRefMutIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_iter_mut`]: /hashbrown/struct.HashTable.html#method.par_iter_mut
|
||||
/// [`HashTable`]: /hashbrown/struct.HashTable.html
|
||||
/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html
|
||||
pub struct ParIterMut<'a, T> {
|
||||
inner: RawParIter<T>,
|
||||
marker: PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Send> ParallelIterator for ParIterMut<'a, T> {
|
||||
type Item = &'a mut T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner
|
||||
.map(|x| unsafe { x.as_mut() })
|
||||
.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for ParIterMut<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: self.inner.clone(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel iterator over entries of a consumed map.
|
||||
///
|
||||
/// This iterator is created by the [`into_par_iter`] method on [`HashTable`]
|
||||
/// (provided by the [`IntoParallelIterator`] trait).
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`into_par_iter`]: /hashbrown/struct.HashTable.html#method.into_par_iter
|
||||
/// [`HashTable`]: /hashbrown/struct.HashTable.html
|
||||
/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html
|
||||
pub struct IntoParIter<T, A: Allocator = Global> {
|
||||
inner: RawIntoParIter<T, A>,
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send> ParallelIterator for IntoParIter<T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoParIter<T, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: unsafe { self.inner.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parallel draining iterator over entries of a map.
|
||||
///
|
||||
/// This iterator is created by the [`par_drain`] method on [`HashTable`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// [`par_drain`]: /hashbrown/struct.HashTable.html#method.par_drain
|
||||
/// [`HashTable`]: /hashbrown/struct.HashTable.html
|
||||
pub struct ParDrain<'a, T, A: Allocator = Global> {
|
||||
inner: RawParDrain<'a, T, A>,
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Sync> ParallelIterator for ParDrain<'_, T, A> {
|
||||
type Item = T;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn drive_unindexed<C>(self, consumer: C) -> C::Result
|
||||
where
|
||||
C: UnindexedConsumer<Self::Item>,
|
||||
{
|
||||
self.inner.drive_unindexed(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, A: Allocator> fmt::Debug for ParDrain<'_, T, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ParIter {
|
||||
inner: unsafe { self.inner.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator> HashTable<T, A> {
|
||||
/// Consumes (potentially in parallel) all values in an arbitrary order,
|
||||
/// while preserving the map's allocated memory for reuse.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn par_drain(&mut self) -> ParDrain<'_, T, A> {
|
||||
ParDrain {
|
||||
inner: self.raw.par_drain(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send, A: Allocator + Send> IntoParallelIterator for HashTable<T, A> {
|
||||
type Item = T;
|
||||
type Iter = IntoParIter<T, A>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
IntoParIter {
|
||||
inner: self.raw.into_par_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Sync, A: Allocator> IntoParallelIterator for &'a HashTable<T, A> {
|
||||
type Item = &'a T;
|
||||
type Iter = ParIter<'a, T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIter {
|
||||
inner: unsafe { self.raw.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Send, A: Allocator> IntoParallelIterator for &'a mut HashTable<T, A> {
|
||||
type Item = &'a mut T;
|
||||
type Iter = ParIterMut<'a, T>;
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn into_par_iter(self) -> Self::Iter {
|
||||
ParIterMut {
|
||||
inner: unsafe { self.raw.par_iter() },
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_par_table {
|
||||
use alloc::vec::Vec;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::{
|
||||
hash_map::{make_hash, DefaultHashBuilder},
|
||||
hash_table::HashTable,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_iterate() {
|
||||
let hasher = DefaultHashBuilder::default();
|
||||
let mut a = HashTable::new();
|
||||
for i in 0..32 {
|
||||
a.insert_unique(make_hash(&hasher, &i), i, |x| make_hash(&hasher, x));
|
||||
}
|
||||
let observed = AtomicUsize::new(0);
|
||||
a.par_iter().for_each(|k| {
|
||||
observed.fetch_or(1 << *k, Ordering::Relaxed);
|
||||
});
|
||||
assert_eq!(observed.into_inner(), 0xFFFF_FFFF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter() {
|
||||
let hasher = DefaultHashBuilder::default();
|
||||
let hs = {
|
||||
let mut hs = HashTable::new();
|
||||
|
||||
hs.insert_unique(make_hash(&hasher, &'a'), 'a', |x| make_hash(&hasher, x));
|
||||
hs.insert_unique(make_hash(&hasher, &'b'), 'b', |x| make_hash(&hasher, x));
|
||||
|
||||
hs
|
||||
};
|
||||
|
||||
let v = hs.into_par_iter().collect::<Vec<char>>();
|
||||
assert!(v == ['a', 'b'] || v == ['b', 'a']);
|
||||
}
|
||||
}
|
||||
125
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs
vendored
Normal file
125
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
use crate::HashMap;
|
||||
use core::{
|
||||
borrow::Borrow,
|
||||
hash::{BuildHasher, Hash},
|
||||
};
|
||||
use rkyv::{
|
||||
collections::hash_map::{ArchivedHashMap, HashMapResolver},
|
||||
ser::{ScratchSpace, Serializer},
|
||||
Archive, Deserialize, Fallible, Serialize,
|
||||
};
|
||||
|
||||
impl<K: Archive + Hash + Eq, V: Archive, S> Archive for HashMap<K, V, S>
|
||||
where
|
||||
K::Archived: Hash + Eq,
|
||||
{
|
||||
type Archived = ArchivedHashMap<K::Archived, V::Archived>;
|
||||
type Resolver = HashMapResolver;
|
||||
|
||||
#[inline]
|
||||
unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
|
||||
ArchivedHashMap::resolve_from_len(self.len(), pos, resolver, out);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, S, RandomState> Serialize<S> for HashMap<K, V, RandomState>
|
||||
where
|
||||
K: Serialize<S> + Hash + Eq,
|
||||
K::Archived: Hash + Eq,
|
||||
V: Serialize<S>,
|
||||
S: Serializer + ScratchSpace + ?Sized,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
|
||||
unsafe { ArchivedHashMap::serialize_from_iter(self.iter(), serializer) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Archive + Hash + Eq, V: Archive, D: Fallible + ?Sized, S: Default + BuildHasher>
|
||||
Deserialize<HashMap<K, V, S>, D> for ArchivedHashMap<K::Archived, V::Archived>
|
||||
where
|
||||
K::Archived: Deserialize<K, D> + Hash + Eq,
|
||||
V::Archived: Deserialize<V, D>,
|
||||
{
|
||||
#[inline]
|
||||
fn deserialize(&self, deserializer: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
|
||||
let mut result = HashMap::with_capacity_and_hasher(self.len(), S::default());
|
||||
for (k, v) in self.iter() {
|
||||
result.insert(k.deserialize(deserializer)?, v.deserialize(deserializer)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Borrow<AK>, V, AK: Hash + Eq, AV: PartialEq<V>, S: BuildHasher>
|
||||
PartialEq<HashMap<K, V, S>> for ArchivedHashMap<AK, AV>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &HashMap<K, V, S>) -> bool {
|
||||
if self.len() != other.len() {
|
||||
false
|
||||
} else {
|
||||
self.iter()
|
||||
.all(|(key, value)| other.get(key).map_or(false, |v| value.eq(v)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Borrow<AK>, V, AK: Hash + Eq, AV: PartialEq<V>>
|
||||
PartialEq<ArchivedHashMap<AK, AV>> for HashMap<K, V>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &ArchivedHashMap<AK, AV>) -> bool {
|
||||
other.eq(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::HashMap;
|
||||
use alloc::string::String;
|
||||
use rkyv::{
|
||||
archived_root, check_archived_root,
|
||||
ser::{serializers::AllocSerializer, Serializer},
|
||||
Deserialize, Infallible,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn index_map() {
|
||||
let mut value = HashMap::new();
|
||||
value.insert(String::from("foo"), 10);
|
||||
value.insert(String::from("bar"), 20);
|
||||
value.insert(String::from("baz"), 40);
|
||||
value.insert(String::from("bat"), 80);
|
||||
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
serializer.serialize_value(&value).unwrap();
|
||||
let result = serializer.into_serializer().into_inner();
|
||||
let archived = unsafe { archived_root::<HashMap<String, i32>>(result.as_ref()) };
|
||||
|
||||
assert_eq!(value.len(), archived.len());
|
||||
for (k, v) in value.iter() {
|
||||
let (ak, av) = archived.get_key_value(k.as_str()).unwrap();
|
||||
assert_eq!(k, ak);
|
||||
assert_eq!(v, av);
|
||||
}
|
||||
|
||||
let deserialized: HashMap<String, i32> = archived.deserialize(&mut Infallible).unwrap();
|
||||
assert_eq!(value, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_index_map() {
|
||||
let mut value = HashMap::new();
|
||||
value.insert(String::from("foo"), 10);
|
||||
value.insert(String::from("bar"), 20);
|
||||
value.insert(String::from("baz"), 40);
|
||||
value.insert(String::from("bat"), 80);
|
||||
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
serializer.serialize_value(&value).unwrap();
|
||||
let result = serializer.into_serializer().into_inner();
|
||||
check_archived_root::<HashMap<String, i32>>(result.as_ref())
|
||||
.expect("failed to validate archived index map");
|
||||
}
|
||||
}
|
||||
123
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs
vendored
Normal file
123
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
use crate::HashSet;
|
||||
use core::{
|
||||
borrow::Borrow,
|
||||
hash::{BuildHasher, Hash},
|
||||
};
|
||||
use rkyv::{
|
||||
collections::hash_set::{ArchivedHashSet, HashSetResolver},
|
||||
ser::{ScratchSpace, Serializer},
|
||||
Archive, Deserialize, Fallible, Serialize,
|
||||
};
|
||||
|
||||
impl<K: Archive + Hash + Eq, S> Archive for HashSet<K, S>
|
||||
where
|
||||
K::Archived: Hash + Eq,
|
||||
{
|
||||
type Archived = ArchivedHashSet<K::Archived>;
|
||||
type Resolver = HashSetResolver;
|
||||
|
||||
#[inline]
|
||||
unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
|
||||
ArchivedHashSet::<K::Archived>::resolve_from_len(self.len(), pos, resolver, out);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, S, RS> Serialize<S> for HashSet<K, RS>
|
||||
where
|
||||
K::Archived: Hash + Eq,
|
||||
K: Serialize<S> + Hash + Eq,
|
||||
S: ScratchSpace + Serializer + ?Sized,
|
||||
{
|
||||
#[inline]
|
||||
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
|
||||
unsafe { ArchivedHashSet::serialize_from_iter(self.iter(), serializer) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, D, S> Deserialize<HashSet<K, S>, D> for ArchivedHashSet<K::Archived>
|
||||
where
|
||||
K: Archive + Hash + Eq,
|
||||
K::Archived: Deserialize<K, D> + Hash + Eq,
|
||||
D: Fallible + ?Sized,
|
||||
S: Default + BuildHasher,
|
||||
{
|
||||
#[inline]
|
||||
fn deserialize(&self, deserializer: &mut D) -> Result<HashSet<K, S>, D::Error> {
|
||||
let mut result = HashSet::with_hasher(S::default());
|
||||
for k in self.iter() {
|
||||
result.insert(k.deserialize(deserializer)?);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Borrow<AK>, AK: Hash + Eq, S: BuildHasher> PartialEq<HashSet<K, S>>
|
||||
for ArchivedHashSet<AK>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &HashSet<K, S>) -> bool {
|
||||
if self.len() != other.len() {
|
||||
false
|
||||
} else {
|
||||
self.iter().all(|key| other.get(key).is_some())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq + Borrow<AK>, AK: Hash + Eq, S: BuildHasher> PartialEq<ArchivedHashSet<AK>>
|
||||
for HashSet<K, S>
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &ArchivedHashSet<AK>) -> bool {
|
||||
other.eq(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::HashSet;
|
||||
use alloc::string::String;
|
||||
use rkyv::{
|
||||
archived_root, check_archived_root,
|
||||
ser::{serializers::AllocSerializer, Serializer},
|
||||
Deserialize, Infallible,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn index_set() {
|
||||
let mut value = HashSet::new();
|
||||
value.insert(String::from("foo"));
|
||||
value.insert(String::from("bar"));
|
||||
value.insert(String::from("baz"));
|
||||
value.insert(String::from("bat"));
|
||||
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
serializer.serialize_value(&value).unwrap();
|
||||
let result = serializer.into_serializer().into_inner();
|
||||
let archived = unsafe { archived_root::<HashSet<String>>(result.as_ref()) };
|
||||
|
||||
assert_eq!(value.len(), archived.len());
|
||||
for k in value.iter() {
|
||||
let ak = archived.get(k.as_str()).unwrap();
|
||||
assert_eq!(k, ak);
|
||||
}
|
||||
|
||||
let deserialized: HashSet<String> = archived.deserialize(&mut Infallible).unwrap();
|
||||
assert_eq!(value, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_index_set() {
|
||||
let mut value = HashSet::new();
|
||||
value.insert(String::from("foo"));
|
||||
value.insert(String::from("bar"));
|
||||
value.insert(String::from("baz"));
|
||||
value.insert(String::from("bat"));
|
||||
|
||||
let mut serializer = AllocSerializer::<4096>::default();
|
||||
serializer.serialize_value(&value).unwrap();
|
||||
let result = serializer.into_serializer().into_inner();
|
||||
check_archived_root::<HashSet<String>>(result.as_ref())
|
||||
.expect("failed to validate archived index set");
|
||||
}
|
||||
}
|
||||
2
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs
vendored
Normal file
2
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
mod hash_map;
|
||||
mod hash_set;
|
||||
220
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/serde.rs
vendored
Normal file
220
third_party/crates/hashbrown-0.14.5/src/external_trait_impls/serde.rs
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
mod size_hint {
|
||||
use core::cmp;
|
||||
|
||||
/// This presumably exists to prevent denial of service attacks.
|
||||
///
|
||||
/// Original discussion: https://github.com/serde-rs/serde/issues/1114.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub(super) fn cautious(hint: Option<usize>) -> usize {
|
||||
cmp::min(hint.unwrap_or(0), 4096)
|
||||
}
|
||||
}
|
||||
|
||||
mod map {
|
||||
use crate::raw::Allocator;
|
||||
use core::fmt;
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use core::marker::PhantomData;
|
||||
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
|
||||
use crate::hash_map::HashMap;
|
||||
|
||||
use super::size_hint;
|
||||
|
||||
impl<K, V, H, A> Serialize for HashMap<K, V, H, A>
|
||||
where
|
||||
K: Serialize + Eq + Hash,
|
||||
V: Serialize,
|
||||
H: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_map(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, K, V, S, A> Deserialize<'de> for HashMap<K, V, S, A>
|
||||
where
|
||||
K: Deserialize<'de> + Eq + Hash,
|
||||
V: Deserialize<'de>,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator + Default,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct MapVisitor<K, V, S, A>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
marker: PhantomData<HashMap<K, V, S, A>>,
|
||||
}
|
||||
|
||||
impl<'de, K, V, S, A> Visitor<'de> for MapVisitor<K, V, S, A>
|
||||
where
|
||||
K: Deserialize<'de> + Eq + Hash,
|
||||
V: Deserialize<'de>,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator + Default,
|
||||
{
|
||||
type Value = HashMap<K, V, S, A>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a map")
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: MapAccess<'de>,
|
||||
{
|
||||
let mut values = HashMap::with_capacity_and_hasher_in(
|
||||
size_hint::cautious(map.size_hint()),
|
||||
S::default(),
|
||||
A::default(),
|
||||
);
|
||||
|
||||
while let Some((key, value)) = map.next_entry()? {
|
||||
values.insert(key, value);
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
|
||||
let visitor = MapVisitor {
|
||||
marker: PhantomData,
|
||||
};
|
||||
deserializer.deserialize_map(visitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod set {
|
||||
use crate::raw::Allocator;
|
||||
use core::fmt;
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use core::marker::PhantomData;
|
||||
use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
|
||||
use crate::hash_set::HashSet;
|
||||
|
||||
use super::size_hint;
|
||||
|
||||
impl<T, H, A> Serialize for HashSet<T, H, A>
|
||||
where
|
||||
T: Serialize + Eq + Hash,
|
||||
H: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.collect_seq(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T, S, A> Deserialize<'de> for HashSet<T, S, A>
|
||||
where
|
||||
T: Deserialize<'de> + Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator + Default,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct SeqVisitor<T, S, A>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
marker: PhantomData<HashSet<T, S, A>>,
|
||||
}
|
||||
|
||||
impl<'de, T, S, A> Visitor<'de> for SeqVisitor<T, S, A>
|
||||
where
|
||||
T: Deserialize<'de> + Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator + Default,
|
||||
{
|
||||
type Value = HashSet<T, S, A>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a sequence")
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn visit_seq<M>(self, mut seq: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: SeqAccess<'de>,
|
||||
{
|
||||
let mut values = HashSet::with_capacity_and_hasher_in(
|
||||
size_hint::cautious(seq.size_hint()),
|
||||
S::default(),
|
||||
A::default(),
|
||||
);
|
||||
|
||||
while let Some(value) = seq.next_element()? {
|
||||
values.insert(value);
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
|
||||
let visitor = SeqVisitor {
|
||||
marker: PhantomData,
|
||||
};
|
||||
deserializer.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct SeqInPlaceVisitor<'a, T, S, A>(&'a mut HashSet<T, S, A>)
|
||||
where
|
||||
A: Allocator;
|
||||
|
||||
impl<'a, 'de, T, S, A> Visitor<'de> for SeqInPlaceVisitor<'a, T, S, A>
|
||||
where
|
||||
T: Deserialize<'de> + Eq + Hash,
|
||||
S: BuildHasher + Default,
|
||||
A: Allocator,
|
||||
{
|
||||
type Value = ();
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a sequence")
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
fn visit_seq<M>(self, mut seq: M) -> Result<Self::Value, M::Error>
|
||||
where
|
||||
M: SeqAccess<'de>,
|
||||
{
|
||||
self.0.clear();
|
||||
self.0.reserve(size_hint::cautious(seq.size_hint()));
|
||||
|
||||
while let Some(value) = seq.next_element()? {
|
||||
self.0.insert(value);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_seq(SeqInPlaceVisitor(place))
|
||||
}
|
||||
}
|
||||
}
|
||||
188
third_party/crates/hashbrown-0.14.5/src/lib.rs
vendored
Normal file
188
third_party/crates/hashbrown-0.14.5/src/lib.rs
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
//! This crate is a Rust port of Google's high-performance [SwissTable] hash
|
||||
//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap`
|
||||
//! and `HashSet` types.
|
||||
//!
|
||||
//! The original C++ version of [SwissTable] can be found [here], and this
|
||||
//! [CppCon talk] gives an overview of how the algorithm works.
|
||||
//!
|
||||
//! [SwissTable]: https://abseil.io/blog/20180927-swisstables
|
||||
//! [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h
|
||||
//! [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4
|
||||
|
||||
#![no_std]
|
||||
#![cfg_attr(
|
||||
feature = "nightly",
|
||||
feature(
|
||||
test,
|
||||
core_intrinsics,
|
||||
dropck_eyepatch,
|
||||
min_specialization,
|
||||
extend_one,
|
||||
allocator_api,
|
||||
slice_ptr_get,
|
||||
maybe_uninit_array_assume_init,
|
||||
strict_provenance
|
||||
)
|
||||
)]
|
||||
#![allow(
|
||||
clippy::doc_markdown,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::option_if_let_else,
|
||||
clippy::redundant_else,
|
||||
clippy::manual_map,
|
||||
clippy::missing_safety_doc,
|
||||
clippy::missing_errors_doc
|
||||
)]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![cfg_attr(feature = "nightly", warn(fuzzy_provenance_casts))]
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
#[cfg_attr(test, macro_use)]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
#[cfg(doctest)]
|
||||
doc_comment::doctest!("../README.md");
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
#[cfg(feature = "raw")]
|
||||
/// Experimental and unsafe `RawTable` API. This module is only available if the
|
||||
/// `raw` feature is enabled.
|
||||
pub mod raw {
|
||||
// The RawTable API is still experimental and is not properly documented yet.
|
||||
#[allow(missing_docs)]
|
||||
#[path = "mod.rs"]
|
||||
mod inner;
|
||||
pub use inner::*;
|
||||
|
||||
#[cfg(feature = "rayon")]
|
||||
/// [rayon]-based parallel iterator types for hash maps.
|
||||
/// You will rarely need to interact with it directly unless you have need
|
||||
/// to name one of the iterator types.
|
||||
///
|
||||
/// [rayon]: https://docs.rs/rayon/1.0/rayon
|
||||
pub mod rayon {
|
||||
pub use crate::external_trait_impls::rayon::raw::*;
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "raw"))]
|
||||
mod raw;
|
||||
|
||||
mod external_trait_impls;
|
||||
mod map;
|
||||
#[cfg(feature = "rustc-internal-api")]
|
||||
mod rustc_entry;
|
||||
mod scopeguard;
|
||||
mod set;
|
||||
mod table;
|
||||
|
||||
pub mod hash_map {
|
||||
//! A hash map implemented with quadratic probing and SIMD lookup.
|
||||
pub use crate::map::*;
|
||||
|
||||
#[cfg(feature = "rustc-internal-api")]
|
||||
pub use crate::rustc_entry::*;
|
||||
|
||||
#[cfg(feature = "rayon")]
|
||||
/// [rayon]-based parallel iterator types for hash maps.
|
||||
/// You will rarely need to interact with it directly unless you have need
|
||||
/// to name one of the iterator types.
|
||||
///
|
||||
/// [rayon]: https://docs.rs/rayon/1.0/rayon
|
||||
pub mod rayon {
|
||||
pub use crate::external_trait_impls::rayon::map::*;
|
||||
}
|
||||
}
|
||||
pub mod hash_set {
|
||||
//! A hash set implemented as a `HashMap` where the value is `()`.
|
||||
pub use crate::set::*;
|
||||
|
||||
#[cfg(feature = "rayon")]
|
||||
/// [rayon]-based parallel iterator types for hash sets.
|
||||
/// You will rarely need to interact with it directly unless you have need
|
||||
/// to name one of the iterator types.
|
||||
///
|
||||
/// [rayon]: https://docs.rs/rayon/1.0/rayon
|
||||
pub mod rayon {
|
||||
pub use crate::external_trait_impls::rayon::set::*;
|
||||
}
|
||||
}
|
||||
pub mod hash_table {
|
||||
//! A hash table implemented with quadratic probing and SIMD lookup.
|
||||
pub use crate::table::*;
|
||||
|
||||
#[cfg(feature = "rayon")]
|
||||
/// [rayon]-based parallel iterator types for hash tables.
|
||||
/// You will rarely need to interact with it directly unless you have need
|
||||
/// to name one of the iterator types.
|
||||
///
|
||||
/// [rayon]: https://docs.rs/rayon/1.0/rayon
|
||||
pub mod rayon {
|
||||
pub use crate::external_trait_impls::rayon::table::*;
|
||||
}
|
||||
}
|
||||
|
||||
pub use crate::map::HashMap;
|
||||
pub use crate::set::HashSet;
|
||||
pub use crate::table::HashTable;
|
||||
|
||||
#[cfg(feature = "equivalent")]
|
||||
pub use equivalent::Equivalent;
|
||||
|
||||
// This is only used as a fallback when building as part of `std`.
|
||||
#[cfg(not(feature = "equivalent"))]
|
||||
/// Key equivalence trait.
|
||||
///
|
||||
/// This trait defines the function used to compare the input value with the
|
||||
/// map keys (or set values) during a lookup operation such as [`HashMap::get`]
|
||||
/// or [`HashSet::contains`].
|
||||
/// It is provided with a blanket implementation based on the
|
||||
/// [`Borrow`](core::borrow::Borrow) trait.
|
||||
///
|
||||
/// # Correctness
|
||||
///
|
||||
/// Equivalent values must hash to the same value.
|
||||
pub trait Equivalent<K: ?Sized> {
|
||||
/// Checks if this value is equivalent to the given key.
|
||||
///
|
||||
/// Returns `true` if both values are equivalent, and `false` otherwise.
|
||||
///
|
||||
/// # Correctness
|
||||
///
|
||||
/// When this function returns `true`, both `self` and `key` must hash to
|
||||
/// the same value.
|
||||
fn equivalent(&self, key: &K) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "equivalent"))]
|
||||
impl<Q: ?Sized, K: ?Sized> Equivalent<K> for Q
|
||||
where
|
||||
Q: Eq,
|
||||
K: core::borrow::Borrow<Q>,
|
||||
{
|
||||
fn equivalent(&self, key: &K) -> bool {
|
||||
self == key.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
/// The error type for `try_reserve` methods.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum TryReserveError {
|
||||
/// Error due to the computed capacity exceeding the collection's maximum
|
||||
/// (usually `isize::MAX` bytes).
|
||||
CapacityOverflow,
|
||||
|
||||
/// The memory allocator returned an error
|
||||
AllocError {
|
||||
/// The layout of the allocation request that failed.
|
||||
layout: alloc::alloc::Layout,
|
||||
},
|
||||
}
|
||||
70
third_party/crates/hashbrown-0.14.5/src/macros.rs
vendored
Normal file
70
third_party/crates/hashbrown-0.14.5/src/macros.rs
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// See the cfg-if crate.
|
||||
#[allow(unused_macro_rules)]
|
||||
macro_rules! cfg_if {
|
||||
// match if/else chains with a final `else`
|
||||
($(
|
||||
if #[cfg($($meta:meta),*)] { $($it:item)* }
|
||||
) else * else {
|
||||
$($it2:item)*
|
||||
}) => {
|
||||
cfg_if! {
|
||||
@__items
|
||||
() ;
|
||||
$( ( ($($meta),*) ($($it)*) ), )*
|
||||
( () ($($it2)*) ),
|
||||
}
|
||||
};
|
||||
|
||||
// match if/else chains lacking a final `else`
|
||||
(
|
||||
if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
|
||||
$(
|
||||
else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
|
||||
)*
|
||||
) => {
|
||||
cfg_if! {
|
||||
@__items
|
||||
() ;
|
||||
( ($($i_met),*) ($($i_it)*) ),
|
||||
$( ( ($($e_met),*) ($($e_it)*) ), )*
|
||||
( () () ),
|
||||
}
|
||||
};
|
||||
|
||||
// Internal and recursive macro to emit all the items
|
||||
//
|
||||
// Collects all the negated cfgs in a list at the beginning and after the
|
||||
// semicolon is all the remaining items
|
||||
(@__items ($($not:meta,)*) ; ) => {};
|
||||
(@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
|
||||
// Emit all items within one block, applying an appropriate #[cfg]. The
|
||||
// #[cfg] will require all `$m` matchers specified and must also negate
|
||||
// all previous matchers.
|
||||
cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* }
|
||||
|
||||
// Recurse to emit all other items in `$rest`, and when we do so add all
|
||||
// our `$m` matchers to the list of `$not` matchers as future emissions
|
||||
// will have to negate everything we just matched as well.
|
||||
cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
|
||||
};
|
||||
|
||||
// Internal macro to Apply a cfg attribute to a list of items
|
||||
(@__apply $m:meta, $($it:item)*) => {
|
||||
$(#[$m] $it)*
|
||||
};
|
||||
}
|
||||
|
||||
// Helper macro for specialization. This also helps avoid parse errors if the
|
||||
// default fn syntax for specialization changes in the future.
|
||||
#[cfg(feature = "nightly")]
|
||||
macro_rules! default_fn {
|
||||
(#[$($a:tt)*] $($tt:tt)*) => {
|
||||
#[$($a)*] default $($tt)*
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
macro_rules! default_fn {
|
||||
($($tt:tt)*) => {
|
||||
$($tt)*
|
||||
}
|
||||
}
|
||||
8960
third_party/crates/hashbrown-0.14.5/src/map.rs
vendored
Normal file
8960
third_party/crates/hashbrown-0.14.5/src/map.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
86
third_party/crates/hashbrown-0.14.5/src/raw/alloc.rs
vendored
Normal file
86
third_party/crates/hashbrown-0.14.5/src/raw/alloc.rs
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
pub(crate) use self::inner::{do_alloc, Allocator, Global};
|
||||
|
||||
// Nightly-case.
|
||||
// Use unstable `allocator_api` feature.
|
||||
// This is compatible with `allocator-api2` which can be enabled or not.
|
||||
// This is used when building for `std`.
|
||||
#[cfg(feature = "nightly")]
|
||||
mod inner {
|
||||
use crate::alloc::alloc::Layout;
|
||||
pub use crate::alloc::alloc::{Allocator, Global};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
#[allow(clippy::map_err_ignore)]
|
||||
pub(crate) fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> {
|
||||
match alloc.allocate(layout) {
|
||||
Ok(ptr) => Ok(ptr.as_non_null_ptr()),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Basic non-nightly case.
|
||||
// This uses `allocator-api2` enabled by default.
|
||||
// If any crate enables "nightly" in `allocator-api2`,
|
||||
// this will be equivalent to the nightly case,
|
||||
// since `allocator_api2::alloc::Allocator` would be re-export of
|
||||
// `core::alloc::Allocator`.
|
||||
#[cfg(all(not(feature = "nightly"), feature = "allocator-api2"))]
|
||||
mod inner {
|
||||
use crate::alloc::alloc::Layout;
|
||||
pub use allocator_api2::alloc::{Allocator, Global};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
#[allow(clippy::map_err_ignore)]
|
||||
pub(crate) fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> {
|
||||
match alloc.allocate(layout) {
|
||||
Ok(ptr) => Ok(ptr.cast()),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No-defaults case.
|
||||
// When building with default-features turned off and
|
||||
// neither `nightly` nor `allocator-api2` is enabled,
|
||||
// this will be used.
|
||||
// Making it impossible to use any custom allocator with collections defined
|
||||
// in this crate.
|
||||
// Any crate in build-tree can enable `allocator-api2`,
|
||||
// or `nightly` without disturbing users that don't want to use it.
|
||||
#[cfg(not(any(feature = "nightly", feature = "allocator-api2")))]
|
||||
mod inner {
|
||||
use crate::alloc::alloc::{alloc, dealloc, Layout};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
#[allow(clippy::missing_safety_doc)] // not exposed outside of this crate
|
||||
pub unsafe trait Allocator {
|
||||
fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()>;
|
||||
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Global;
|
||||
|
||||
unsafe impl Allocator for Global {
|
||||
#[inline]
|
||||
fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()> {
|
||||
unsafe { NonNull::new(alloc(layout)).ok_or(()) }
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
|
||||
dealloc(ptr.as_ptr(), layout);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Global {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Global
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> {
|
||||
alloc.allocate(layout)
|
||||
}
|
||||
}
|
||||
133
third_party/crates/hashbrown-0.14.5/src/raw/bitmask.rs
vendored
Normal file
133
third_party/crates/hashbrown-0.14.5/src/raw/bitmask.rs
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
use super::imp::{
|
||||
BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE,
|
||||
};
|
||||
|
||||
/// A bit mask which contains the result of a `Match` operation on a `Group` and
|
||||
/// allows iterating through them.
|
||||
///
|
||||
/// The bit mask is arranged so that low-order bits represent lower memory
|
||||
/// addresses for group match results.
|
||||
///
|
||||
/// For implementation reasons, the bits in the set may be sparsely packed with
|
||||
/// groups of 8 bits representing one element. If any of these bits are non-zero
|
||||
/// then this element is considered to true in the mask. If this is the
|
||||
/// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be
|
||||
/// performed on counts/indices to normalize this difference. `BITMASK_MASK` is
|
||||
/// similarly a mask of all the actually-used bits.
|
||||
///
|
||||
/// To iterate over a bit mask, it must be converted to a form where only 1 bit
|
||||
/// is set per element. This is done by applying `BITMASK_ITER_MASK` on the
|
||||
/// mask bits.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct BitMask(pub(crate) BitMaskWord);
|
||||
|
||||
#[allow(clippy::use_self)]
|
||||
impl BitMask {
|
||||
/// Returns a new `BitMask` with all bits inverted.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn invert(self) -> Self {
|
||||
BitMask(self.0 ^ BITMASK_MASK)
|
||||
}
|
||||
|
||||
/// Returns a new `BitMask` with the lowest bit removed.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
fn remove_lowest_bit(self) -> Self {
|
||||
BitMask(self.0 & (self.0 - 1))
|
||||
}
|
||||
|
||||
/// Returns whether the `BitMask` has at least one set bit.
|
||||
#[inline]
|
||||
pub(crate) fn any_bit_set(self) -> bool {
|
||||
self.0 != 0
|
||||
}
|
||||
|
||||
/// Returns the first set bit in the `BitMask`, if there is one.
|
||||
#[inline]
|
||||
pub(crate) fn lowest_set_bit(self) -> Option<usize> {
|
||||
if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) {
|
||||
Some(Self::nonzero_trailing_zeros(nonzero))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of trailing zeroes in the `BitMask`.
|
||||
#[inline]
|
||||
pub(crate) fn trailing_zeros(self) -> usize {
|
||||
// ARM doesn't have a trailing_zeroes instruction, and instead uses
|
||||
// reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM
|
||||
// versions (pre-ARMv7) don't have RBIT and need to emulate it
|
||||
// instead. Since we only have 1 bit set in each byte on ARM, we can
|
||||
// use swap_bytes (REV) + leading_zeroes instead.
|
||||
if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 {
|
||||
self.0.swap_bytes().leading_zeros() as usize / BITMASK_STRIDE
|
||||
} else {
|
||||
self.0.trailing_zeros() as usize / BITMASK_STRIDE
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as above but takes a `NonZeroBitMaskWord`.
|
||||
#[inline]
|
||||
fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize {
|
||||
if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 {
|
||||
// SAFETY: A byte-swapped non-zero value is still non-zero.
|
||||
let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) };
|
||||
swapped.leading_zeros() as usize / BITMASK_STRIDE
|
||||
} else {
|
||||
nonzero.trailing_zeros() as usize / BITMASK_STRIDE
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of leading zeroes in the `BitMask`.
|
||||
#[inline]
|
||||
pub(crate) fn leading_zeros(self) -> usize {
|
||||
self.0.leading_zeros() as usize / BITMASK_STRIDE
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for BitMask {
|
||||
type Item = usize;
|
||||
type IntoIter = BitMaskIter;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> BitMaskIter {
|
||||
// A BitMask only requires each element (group of bits) to be non-zero.
|
||||
// However for iteration we need each element to only contain 1 bit.
|
||||
BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK))
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over the contents of a `BitMask`, returning the indices of set
|
||||
/// bits.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct BitMaskIter(pub(crate) BitMask);
|
||||
|
||||
impl BitMaskIter {
|
||||
/// Flip the bit in the mask for the entry at the given index.
|
||||
///
|
||||
/// Returns the bit's previous state.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
#[cfg(feature = "raw")]
|
||||
pub(crate) unsafe fn flip(&mut self, index: usize) -> bool {
|
||||
// NOTE: The + BITMASK_STRIDE - 1 is to set the high bit.
|
||||
let mask = 1 << (index * BITMASK_STRIDE + BITMASK_STRIDE - 1);
|
||||
self.0 .0 ^= mask;
|
||||
// The bit was set if the bit is now 0.
|
||||
self.0 .0 & mask == 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for BitMaskIter {
|
||||
type Item = usize;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<usize> {
|
||||
let bit = self.0.lowest_set_bit()?;
|
||||
self.0 = self.0.remove_lowest_bit();
|
||||
Some(bit)
|
||||
}
|
||||
}
|
||||
157
third_party/crates/hashbrown-0.14.5/src/raw/generic.rs
vendored
Normal file
157
third_party/crates/hashbrown-0.14.5/src/raw/generic.rs
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
use super::bitmask::BitMask;
|
||||
use super::EMPTY;
|
||||
use core::{mem, ptr};
|
||||
|
||||
// Use the native word size as the group size. Using a 64-bit group size on
|
||||
// a 32-bit architecture will just end up being more expensive because
|
||||
// shifts and multiplies will need to be emulated.
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_pointer_width = "64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "wasm32",
|
||||
))] {
|
||||
type GroupWord = u64;
|
||||
type NonZeroGroupWord = core::num::NonZeroU64;
|
||||
} else {
|
||||
type GroupWord = u32;
|
||||
type NonZeroGroupWord = core::num::NonZeroU32;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type BitMaskWord = GroupWord;
|
||||
pub(crate) type NonZeroBitMaskWord = NonZeroGroupWord;
|
||||
pub(crate) const BITMASK_STRIDE: usize = 8;
|
||||
// We only care about the highest bit of each byte for the mask.
|
||||
#[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)]
|
||||
pub(crate) const BITMASK_MASK: BitMaskWord = 0x8080_8080_8080_8080_u64 as GroupWord;
|
||||
pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0;
|
||||
|
||||
/// Helper function to replicate a byte across a `GroupWord`.
|
||||
#[inline]
|
||||
fn repeat(byte: u8) -> GroupWord {
|
||||
GroupWord::from_ne_bytes([byte; Group::WIDTH])
|
||||
}
|
||||
|
||||
/// Abstraction over a group of control bytes which can be scanned in
|
||||
/// parallel.
|
||||
///
|
||||
/// This implementation uses a word-sized integer.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct Group(GroupWord);
|
||||
|
||||
// We perform all operations in the native endianness, and convert to
|
||||
// little-endian just before creating a BitMask. The can potentially
|
||||
// enable the compiler to eliminate unnecessary byte swaps if we are
|
||||
// only checking whether a BitMask is empty.
|
||||
#[allow(clippy::use_self)]
|
||||
impl Group {
|
||||
/// Number of bytes in the group.
|
||||
pub(crate) const WIDTH: usize = mem::size_of::<Self>();
|
||||
|
||||
/// Returns a full group of empty bytes, suitable for use as the initial
|
||||
/// value for an empty hash table.
|
||||
///
|
||||
/// This is guaranteed to be aligned to the group size.
|
||||
#[inline]
|
||||
pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] {
|
||||
#[repr(C)]
|
||||
struct AlignedBytes {
|
||||
_align: [Group; 0],
|
||||
bytes: [u8; Group::WIDTH],
|
||||
}
|
||||
const ALIGNED_BYTES: AlignedBytes = AlignedBytes {
|
||||
_align: [],
|
||||
bytes: [EMPTY; Group::WIDTH],
|
||||
};
|
||||
&ALIGNED_BYTES.bytes
|
||||
}
|
||||
|
||||
/// Loads a group of bytes starting at the given address.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)] // unaligned load
|
||||
pub(crate) unsafe fn load(ptr: *const u8) -> Self {
|
||||
Group(ptr::read_unaligned(ptr.cast()))
|
||||
}
|
||||
|
||||
/// Loads a group of bytes starting at the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
Group(ptr::read(ptr.cast()))
|
||||
}
|
||||
|
||||
/// Stores the group of bytes to the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
ptr::write(ptr.cast(), self.0);
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which *may*
|
||||
/// have the given value.
|
||||
///
|
||||
/// This function may return a false positive in certain cases where
|
||||
/// the byte in the group differs from the searched value only in its
|
||||
/// lowest bit. This is fine because:
|
||||
/// - This never happens for `EMPTY` and `DELETED`, only full entries.
|
||||
/// - The check for key equality will catch these.
|
||||
/// - This only happens if there is at least 1 true match.
|
||||
/// - The chance of this happening is very low (< 1% chance per byte).
|
||||
#[inline]
|
||||
pub(crate) fn match_byte(self, byte: u8) -> BitMask {
|
||||
// This algorithm is derived from
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
|
||||
let cmp = self.0 ^ repeat(byte);
|
||||
BitMask((cmp.wrapping_sub(repeat(0x01)) & !cmp & repeat(0x80)).to_le())
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY`.
|
||||
#[inline]
|
||||
pub(crate) fn match_empty(self) -> BitMask {
|
||||
// If the high bit is set, then the byte must be either:
|
||||
// 1111_1111 (EMPTY) or 1000_0000 (DELETED).
|
||||
// So we can just check if the top two bits are 1 by ANDing them.
|
||||
BitMask((self.0 & (self.0 << 1) & repeat(0x80)).to_le())
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY` or `DELETED`.
|
||||
#[inline]
|
||||
pub(crate) fn match_empty_or_deleted(self) -> BitMask {
|
||||
// A byte is EMPTY or DELETED iff the high bit is set
|
||||
BitMask((self.0 & repeat(0x80)).to_le())
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are full.
|
||||
#[inline]
|
||||
pub(crate) fn match_full(self) -> BitMask {
|
||||
self.match_empty_or_deleted().invert()
|
||||
}
|
||||
|
||||
/// Performs the following transformation on all bytes in the group:
|
||||
/// - `EMPTY => EMPTY`
|
||||
/// - `DELETED => EMPTY`
|
||||
/// - `FULL => DELETED`
|
||||
#[inline]
|
||||
pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self {
|
||||
// Map high_bit = 1 (EMPTY or DELETED) to 1111_1111
|
||||
// and high_bit = 0 (FULL) to 1000_0000
|
||||
//
|
||||
// Here's this logic expanded to concrete values:
|
||||
// let full = 1000_0000 (true) or 0000_0000 (false)
|
||||
// !1000_0000 + 1 = 0111_1111 + 1 = 1000_0000 (no carry)
|
||||
// !0000_0000 + 0 = 1111_1111 + 0 = 1111_1111 (no carry)
|
||||
let full = !self.0 & repeat(0x80);
|
||||
Group(!full + (full >> 7))
|
||||
}
|
||||
}
|
||||
4817
third_party/crates/hashbrown-0.14.5/src/raw/mod.rs
vendored
Normal file
4817
third_party/crates/hashbrown-0.14.5/src/raw/mod.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
124
third_party/crates/hashbrown-0.14.5/src/raw/neon.rs
vendored
Normal file
124
third_party/crates/hashbrown-0.14.5/src/raw/neon.rs
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
use super::bitmask::BitMask;
|
||||
use super::EMPTY;
|
||||
use core::arch::aarch64 as neon;
|
||||
use core::mem;
|
||||
use core::num::NonZeroU64;
|
||||
|
||||
pub(crate) type BitMaskWord = u64;
|
||||
pub(crate) type NonZeroBitMaskWord = NonZeroU64;
|
||||
pub(crate) const BITMASK_STRIDE: usize = 8;
|
||||
pub(crate) const BITMASK_MASK: BitMaskWord = !0;
|
||||
pub(crate) const BITMASK_ITER_MASK: BitMaskWord = 0x8080_8080_8080_8080;
|
||||
|
||||
/// Abstraction over a group of control bytes which can be scanned in
|
||||
/// parallel.
|
||||
///
|
||||
/// This implementation uses a 64-bit NEON value.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct Group(neon::uint8x8_t);
|
||||
|
||||
#[allow(clippy::use_self)]
|
||||
impl Group {
|
||||
/// Number of bytes in the group.
|
||||
pub(crate) const WIDTH: usize = mem::size_of::<Self>();
|
||||
|
||||
/// Returns a full group of empty bytes, suitable for use as the initial
|
||||
/// value for an empty hash table.
|
||||
///
|
||||
/// This is guaranteed to be aligned to the group size.
|
||||
#[inline]
|
||||
pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] {
|
||||
#[repr(C)]
|
||||
struct AlignedBytes {
|
||||
_align: [Group; 0],
|
||||
bytes: [u8; Group::WIDTH],
|
||||
}
|
||||
const ALIGNED_BYTES: AlignedBytes = AlignedBytes {
|
||||
_align: [],
|
||||
bytes: [EMPTY; Group::WIDTH],
|
||||
};
|
||||
&ALIGNED_BYTES.bytes
|
||||
}
|
||||
|
||||
/// Loads a group of bytes starting at the given address.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)] // unaligned load
|
||||
pub(crate) unsafe fn load(ptr: *const u8) -> Self {
|
||||
Group(neon::vld1_u8(ptr))
|
||||
}
|
||||
|
||||
/// Loads a group of bytes starting at the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
Group(neon::vld1_u8(ptr))
|
||||
}
|
||||
|
||||
/// Stores the group of bytes to the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
neon::vst1_u8(ptr, self.0);
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which *may*
|
||||
/// have the given value.
|
||||
#[inline]
|
||||
pub(crate) fn match_byte(self, byte: u8) -> BitMask {
|
||||
unsafe {
|
||||
let cmp = neon::vceq_u8(self.0, neon::vdup_n_u8(byte));
|
||||
BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY`.
|
||||
#[inline]
|
||||
pub(crate) fn match_empty(self) -> BitMask {
|
||||
self.match_byte(EMPTY)
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY` or `DELETED`.
|
||||
#[inline]
|
||||
pub(crate) fn match_empty_or_deleted(self) -> BitMask {
|
||||
unsafe {
|
||||
let cmp = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0));
|
||||
BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are full.
|
||||
#[inline]
|
||||
pub(crate) fn match_full(self) -> BitMask {
|
||||
unsafe {
|
||||
let cmp = neon::vcgez_s8(neon::vreinterpret_s8_u8(self.0));
|
||||
BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0))
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs the following transformation on all bytes in the group:
|
||||
/// - `EMPTY => EMPTY`
|
||||
/// - `DELETED => EMPTY`
|
||||
/// - `FULL => DELETED`
|
||||
#[inline]
|
||||
pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self {
|
||||
// Map high_bit = 1 (EMPTY or DELETED) to 1111_1111
|
||||
// and high_bit = 0 (FULL) to 1000_0000
|
||||
//
|
||||
// Here's this logic expanded to concrete values:
|
||||
// let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false)
|
||||
// 1111_1111 | 1000_0000 = 1111_1111
|
||||
// 0000_0000 | 1000_0000 = 1000_0000
|
||||
unsafe {
|
||||
let special = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0));
|
||||
Group(neon::vorr_u8(special, neon::vdup_n_u8(0x80)))
|
||||
}
|
||||
}
|
||||
}
|
||||
149
third_party/crates/hashbrown-0.14.5/src/raw/sse2.rs
vendored
Normal file
149
third_party/crates/hashbrown-0.14.5/src/raw/sse2.rs
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
use super::bitmask::BitMask;
|
||||
use super::EMPTY;
|
||||
use core::mem;
|
||||
use core::num::NonZeroU16;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
use core::arch::x86;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::arch::x86_64 as x86;
|
||||
|
||||
pub(crate) type BitMaskWord = u16;
|
||||
pub(crate) type NonZeroBitMaskWord = NonZeroU16;
|
||||
pub(crate) const BITMASK_STRIDE: usize = 1;
|
||||
pub(crate) const BITMASK_MASK: BitMaskWord = 0xffff;
|
||||
pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0;
|
||||
|
||||
/// Abstraction over a group of control bytes which can be scanned in
|
||||
/// parallel.
|
||||
///
|
||||
/// This implementation uses a 128-bit SSE value.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct Group(x86::__m128i);
|
||||
|
||||
// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859
|
||||
#[allow(clippy::use_self)]
|
||||
impl Group {
|
||||
/// Number of bytes in the group.
|
||||
pub(crate) const WIDTH: usize = mem::size_of::<Self>();
|
||||
|
||||
/// Returns a full group of empty bytes, suitable for use as the initial
|
||||
/// value for an empty hash table.
|
||||
///
|
||||
/// This is guaranteed to be aligned to the group size.
|
||||
#[inline]
|
||||
#[allow(clippy::items_after_statements)]
|
||||
pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] {
|
||||
#[repr(C)]
|
||||
struct AlignedBytes {
|
||||
_align: [Group; 0],
|
||||
bytes: [u8; Group::WIDTH],
|
||||
}
|
||||
const ALIGNED_BYTES: AlignedBytes = AlignedBytes {
|
||||
_align: [],
|
||||
bytes: [EMPTY; Group::WIDTH],
|
||||
};
|
||||
&ALIGNED_BYTES.bytes
|
||||
}
|
||||
|
||||
/// Loads a group of bytes starting at the given address.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)] // unaligned load
|
||||
pub(crate) unsafe fn load(ptr: *const u8) -> Self {
|
||||
Group(x86::_mm_loadu_si128(ptr.cast()))
|
||||
}
|
||||
|
||||
/// Loads a group of bytes starting at the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
Group(x86::_mm_load_si128(ptr.cast()))
|
||||
}
|
||||
|
||||
/// Stores the group of bytes to the given address, which must be
|
||||
/// aligned to `mem::align_of::<Group>()`.
|
||||
#[inline]
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) {
|
||||
// FIXME: use align_offset once it stabilizes
|
||||
debug_assert_eq!(ptr as usize & (mem::align_of::<Self>() - 1), 0);
|
||||
x86::_mm_store_si128(ptr.cast(), self.0);
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which have
|
||||
/// the given value.
|
||||
#[inline]
|
||||
pub(crate) fn match_byte(self, byte: u8) -> BitMask {
|
||||
#[allow(
|
||||
clippy::cast_possible_wrap, // byte: u8 as i8
|
||||
// byte: i32 as u16
|
||||
// note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the
|
||||
// upper 16-bits of the i32 are zeroed:
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_possible_truncation
|
||||
)]
|
||||
unsafe {
|
||||
let cmp = x86::_mm_cmpeq_epi8(self.0, x86::_mm_set1_epi8(byte as i8));
|
||||
BitMask(x86::_mm_movemask_epi8(cmp) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY`.
|
||||
#[inline]
|
||||
pub(crate) fn match_empty(self) -> BitMask {
|
||||
self.match_byte(EMPTY)
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are
|
||||
/// `EMPTY` or `DELETED`.
|
||||
#[inline]
|
||||
pub(crate) fn match_empty_or_deleted(self) -> BitMask {
|
||||
#[allow(
|
||||
// byte: i32 as u16
|
||||
// note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the
|
||||
// upper 16-bits of the i32 are zeroed:
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_possible_truncation
|
||||
)]
|
||||
unsafe {
|
||||
// A byte is EMPTY or DELETED iff the high bit is set
|
||||
BitMask(x86::_mm_movemask_epi8(self.0) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a `BitMask` indicating all bytes in the group which are full.
|
||||
#[inline]
|
||||
pub(crate) fn match_full(&self) -> BitMask {
|
||||
self.match_empty_or_deleted().invert()
|
||||
}
|
||||
|
||||
/// Performs the following transformation on all bytes in the group:
|
||||
/// - `EMPTY => EMPTY`
|
||||
/// - `DELETED => EMPTY`
|
||||
/// - `FULL => DELETED`
|
||||
#[inline]
|
||||
pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self {
|
||||
// Map high_bit = 1 (EMPTY or DELETED) to 1111_1111
|
||||
// and high_bit = 0 (FULL) to 1000_0000
|
||||
//
|
||||
// Here's this logic expanded to concrete values:
|
||||
// let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false)
|
||||
// 1111_1111 | 1000_0000 = 1111_1111
|
||||
// 0000_0000 | 1000_0000 = 1000_0000
|
||||
#[allow(
|
||||
clippy::cast_possible_wrap, // byte: 0x80_u8 as i8
|
||||
)]
|
||||
unsafe {
|
||||
let zero = x86::_mm_setzero_si128();
|
||||
let special = x86::_mm_cmpgt_epi8(zero, self.0);
|
||||
Group(x86::_mm_or_si128(
|
||||
special,
|
||||
x86::_mm_set1_epi8(0x80_u8 as i8),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
630
third_party/crates/hashbrown-0.14.5/src/rustc_entry.rs
vendored
Normal file
630
third_party/crates/hashbrown-0.14.5/src/rustc_entry.rs
vendored
Normal file
@@ -0,0 +1,630 @@
|
||||
use self::RustcEntry::*;
|
||||
use crate::map::{make_hash, Drain, HashMap, IntoIter, Iter, IterMut};
|
||||
use crate::raw::{Allocator, Bucket, Global, RawTable};
|
||||
use core::fmt::{self, Debug};
|
||||
use core::hash::{BuildHasher, Hash};
|
||||
use core::mem;
|
||||
|
||||
impl<K, V, S, A> HashMap<K, V, S, A>
|
||||
where
|
||||
K: Eq + Hash,
|
||||
S: BuildHasher,
|
||||
A: Allocator,
|
||||
{
|
||||
/// Gets the given key's corresponding entry in the map for in-place manipulation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut letters = HashMap::new();
|
||||
///
|
||||
/// for ch in "a short treatise on fungi".chars() {
|
||||
/// let counter = letters.rustc_entry(ch).or_insert(0);
|
||||
/// *counter += 1;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(letters[&'s'], 2);
|
||||
/// assert_eq!(letters[&'t'], 3);
|
||||
/// assert_eq!(letters[&'u'], 1);
|
||||
/// assert_eq!(letters.get(&'y'), None);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> {
|
||||
let hash = make_hash(&self.hash_builder, &key);
|
||||
if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) {
|
||||
RustcEntry::Occupied(RustcOccupiedEntry {
|
||||
key: Some(key),
|
||||
elem,
|
||||
table: &mut self.table,
|
||||
})
|
||||
} else {
|
||||
// Ideally we would put this in VacantEntry::insert, but Entry is not
|
||||
// generic over the BuildHasher and adding a generic parameter would be
|
||||
// a breaking change.
|
||||
self.reserve(1);
|
||||
|
||||
RustcEntry::Vacant(RustcVacantEntry {
|
||||
hash,
|
||||
key,
|
||||
table: &mut self.table,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A view into a single entry in a map, which may either be vacant or occupied.
|
||||
///
|
||||
/// This `enum` is constructed from the [`rustc_entry`] method on [`HashMap`].
|
||||
///
|
||||
/// [`HashMap`]: struct.HashMap.html
|
||||
/// [`rustc_entry`]: struct.HashMap.html#method.rustc_entry
|
||||
pub enum RustcEntry<'a, K, V, A = Global>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
/// An occupied entry.
|
||||
Occupied(RustcOccupiedEntry<'a, K, V, A>),
|
||||
|
||||
/// A vacant entry.
|
||||
Vacant(RustcVacantEntry<'a, K, V, A>),
|
||||
}
|
||||
|
||||
impl<K: Debug, V: Debug, A: Allocator> Debug for RustcEntry<'_, K, V, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
|
||||
Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A view into an occupied entry in a `HashMap`.
|
||||
/// It is part of the [`RustcEntry`] enum.
|
||||
///
|
||||
/// [`RustcEntry`]: enum.RustcEntry.html
|
||||
pub struct RustcOccupiedEntry<'a, K, V, A = Global>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
key: Option<K>,
|
||||
elem: Bucket<(K, V)>,
|
||||
table: &'a mut RawTable<(K, V), A>,
|
||||
}
|
||||
|
||||
unsafe impl<K, V, A> Send for RustcOccupiedEntry<'_, K, V, A>
|
||||
where
|
||||
K: Send,
|
||||
V: Send,
|
||||
A: Allocator + Send,
|
||||
{
|
||||
}
|
||||
unsafe impl<K, V, A> Sync for RustcOccupiedEntry<'_, K, V, A>
|
||||
where
|
||||
K: Sync,
|
||||
V: Sync,
|
||||
A: Allocator + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<K: Debug, V: Debug, A: Allocator> Debug for RustcOccupiedEntry<'_, K, V, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OccupiedEntry")
|
||||
.field("key", self.key())
|
||||
.field("value", self.get())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A view into a vacant entry in a `HashMap`.
|
||||
/// It is part of the [`RustcEntry`] enum.
|
||||
///
|
||||
/// [`RustcEntry`]: enum.RustcEntry.html
|
||||
pub struct RustcVacantEntry<'a, K, V, A = Global>
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
hash: u64,
|
||||
key: K,
|
||||
table: &'a mut RawTable<(K, V), A>,
|
||||
}
|
||||
|
||||
impl<K: Debug, V, A: Allocator> Debug for RustcVacantEntry<'_, K, V, A> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("VacantEntry").field(self.key()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, A: Allocator> RustcEntry<'a, K, V, A> {
|
||||
/// Sets the value of the entry, and returns a RustcOccupiedEntry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// let entry = map.rustc_entry("horseyland").insert(37);
|
||||
///
|
||||
/// assert_eq!(entry.key(), &"horseyland");
|
||||
/// ```
|
||||
pub fn insert(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> {
|
||||
match self {
|
||||
Vacant(entry) => entry.insert_entry(value),
|
||||
Occupied(mut entry) => {
|
||||
entry.insert(value);
|
||||
entry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures a value is in the entry by inserting the default if empty, and returns
|
||||
/// a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
///
|
||||
/// map.rustc_entry("poneyland").or_insert(3);
|
||||
/// assert_eq!(map["poneyland"], 3);
|
||||
///
|
||||
/// *map.rustc_entry("poneyland").or_insert(10) *= 2;
|
||||
/// assert_eq!(map["poneyland"], 6);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn or_insert(self, default: V) -> &'a mut V
|
||||
where
|
||||
K: Hash,
|
||||
{
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
Vacant(entry) => entry.insert(default),
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures a value is in the entry by inserting the result of the default function if empty,
|
||||
/// and returns a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, String> = HashMap::new();
|
||||
/// let s = "hoho".to_string();
|
||||
///
|
||||
/// map.rustc_entry("poneyland").or_insert_with(|| s);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], "hoho".to_string());
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V
|
||||
where
|
||||
K: Hash,
|
||||
{
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
Vacant(entry) => entry.insert(default()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to this entry's key.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn key(&self) -> &K {
|
||||
match *self {
|
||||
Occupied(ref entry) => entry.key(),
|
||||
Vacant(ref entry) => entry.key(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides in-place mutable access to an occupied entry before any
|
||||
/// potential inserts into the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
///
|
||||
/// map.rustc_entry("poneyland")
|
||||
/// .and_modify(|e| { *e += 1 })
|
||||
/// .or_insert(42);
|
||||
/// assert_eq!(map["poneyland"], 42);
|
||||
///
|
||||
/// map.rustc_entry("poneyland")
|
||||
/// .and_modify(|e| { *e += 1 })
|
||||
/// .or_insert(42);
|
||||
/// assert_eq!(map["poneyland"], 43);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn and_modify<F>(self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(&mut V),
|
||||
{
|
||||
match self {
|
||||
Occupied(mut entry) => {
|
||||
f(entry.get_mut());
|
||||
Occupied(entry)
|
||||
}
|
||||
Vacant(entry) => Vacant(entry),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V: Default, A: Allocator> RustcEntry<'a, K, V, A> {
|
||||
/// Ensures a value is in the entry by inserting the default value if empty,
|
||||
/// and returns a mutable reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() {
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, Option<u32>> = HashMap::new();
|
||||
/// map.rustc_entry("poneyland").or_default();
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], None);
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn or_default(self) -> &'a mut V
|
||||
where
|
||||
K: Hash,
|
||||
{
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
Vacant(entry) => entry.insert(Default::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, A: Allocator> RustcOccupiedEntry<'a, K, V, A> {
|
||||
/// Gets a reference to the key in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.rustc_entry("poneyland").or_insert(12);
|
||||
/// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn key(&self) -> &K {
|
||||
unsafe { &self.elem.as_ref().0 }
|
||||
}
|
||||
|
||||
/// Take the ownership of the key and value from the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.rustc_entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") {
|
||||
/// // We delete the entry from the map.
|
||||
/// o.remove_entry();
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map.contains_key("poneyland"), false);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn remove_entry(self) -> (K, V) {
|
||||
unsafe { self.table.remove(self.elem).0 }
|
||||
}
|
||||
|
||||
/// Gets a reference to the value in the entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.rustc_entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") {
|
||||
/// assert_eq!(o.get(), &12);
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn get(&self) -> &V {
|
||||
unsafe { &self.elem.as_ref().1 }
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the value in the entry.
|
||||
///
|
||||
/// If you need a reference to the `RustcOccupiedEntry` which may outlive the
|
||||
/// destruction of the `RustcEntry` value, see [`into_mut`].
|
||||
///
|
||||
/// [`into_mut`]: #method.into_mut
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.rustc_entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 12);
|
||||
/// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") {
|
||||
/// *o.get_mut() += 10;
|
||||
/// assert_eq!(*o.get(), 22);
|
||||
///
|
||||
/// // We can use the same RustcEntry multiple times.
|
||||
/// *o.get_mut() += 2;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 24);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn get_mut(&mut self) -> &mut V {
|
||||
unsafe { &mut self.elem.as_mut().1 }
|
||||
}
|
||||
|
||||
/// Converts the RustcOccupiedEntry into a mutable reference to the value in the entry
|
||||
/// with a lifetime bound to the map itself.
|
||||
///
|
||||
/// If you need multiple references to the `RustcOccupiedEntry`, see [`get_mut`].
|
||||
///
|
||||
/// [`get_mut`]: #method.get_mut
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.rustc_entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 12);
|
||||
/// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") {
|
||||
/// *o.into_mut() += 10;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 22);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn into_mut(self) -> &'a mut V {
|
||||
unsafe { &mut self.elem.as_mut().1 }
|
||||
}
|
||||
|
||||
/// Sets the value of the entry, and returns the entry's old value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.rustc_entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") {
|
||||
/// assert_eq!(o.insert(15), 12);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], 15);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert(&mut self, value: V) -> V {
|
||||
mem::replace(self.get_mut(), value)
|
||||
}
|
||||
|
||||
/// Takes the value out of the entry, and returns it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// map.rustc_entry("poneyland").or_insert(12);
|
||||
///
|
||||
/// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") {
|
||||
/// assert_eq!(o.remove(), 12);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(map.contains_key("poneyland"), false);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn remove(self) -> V {
|
||||
self.remove_entry().1
|
||||
}
|
||||
|
||||
/// Replaces the entry, returning the old key and value. The new key in the hash map will be
|
||||
/// the key used to create this entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_map::{RustcEntry, HashMap};
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
|
||||
/// map.insert(Rc::new("Stringthing".to_string()), 15);
|
||||
///
|
||||
/// let my_key = Rc::new("Stringthing".to_string());
|
||||
///
|
||||
/// if let RustcEntry::Occupied(entry) = map.rustc_entry(my_key) {
|
||||
/// // Also replace the key with a handle to our other key.
|
||||
/// let (old_key, old_value): (Rc<String>, u32) = entry.replace_entry(16);
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn replace_entry(self, value: V) -> (K, V) {
|
||||
let entry = unsafe { self.elem.as_mut() };
|
||||
|
||||
let old_key = mem::replace(&mut entry.0, self.key.unwrap());
|
||||
let old_value = mem::replace(&mut entry.1, value);
|
||||
|
||||
(old_key, old_value)
|
||||
}
|
||||
|
||||
/// Replaces the key in the hash map with the key used to create this entry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::hash_map::{RustcEntry, HashMap};
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut map: HashMap<Rc<String>, u32> = HashMap::new();
|
||||
/// let mut known_strings: Vec<Rc<String>> = Vec::new();
|
||||
///
|
||||
/// // Initialise known strings, run program, etc.
|
||||
///
|
||||
/// reclaim_memory(&mut map, &known_strings);
|
||||
///
|
||||
/// fn reclaim_memory(map: &mut HashMap<Rc<String>, u32>, known_strings: &[Rc<String>] ) {
|
||||
/// for s in known_strings {
|
||||
/// if let RustcEntry::Occupied(entry) = map.rustc_entry(s.clone()) {
|
||||
/// // Replaces the entry's key with our version of it in `known_strings`.
|
||||
/// entry.replace_key();
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn replace_key(self) -> K {
|
||||
let entry = unsafe { self.elem.as_mut() };
|
||||
mem::replace(&mut entry.0, self.key.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V, A: Allocator> RustcVacantEntry<'a, K, V, A> {
|
||||
/// Gets a reference to the key that would be used when inserting a value
|
||||
/// through the `RustcVacantEntry`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
/// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland");
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn key(&self) -> &K {
|
||||
&self.key
|
||||
}
|
||||
|
||||
/// Take ownership of the key.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
///
|
||||
/// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") {
|
||||
/// v.into_key();
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn into_key(self) -> K {
|
||||
self.key
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the RustcVacantEntry's key,
|
||||
/// and returns a mutable reference to it.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
///
|
||||
/// if let RustcEntry::Vacant(o) = map.rustc_entry("poneyland") {
|
||||
/// o.insert(37);
|
||||
/// }
|
||||
/// assert_eq!(map["poneyland"], 37);
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert(self, value: V) -> &'a mut V {
|
||||
unsafe {
|
||||
let bucket = self.table.insert_no_grow(self.hash, (self.key, value));
|
||||
&mut bucket.as_mut().1
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the RustcVacantEntry's key,
|
||||
/// and returns a RustcOccupiedEntry.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use hashbrown::HashMap;
|
||||
/// use hashbrown::hash_map::RustcEntry;
|
||||
///
|
||||
/// let mut map: HashMap<&str, u32> = HashMap::new();
|
||||
///
|
||||
/// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") {
|
||||
/// let o = v.insert_entry(37);
|
||||
/// assert_eq!(o.get(), &37);
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> {
|
||||
let bucket = unsafe { self.table.insert_no_grow(self.hash, (self.key, value)) };
|
||||
RustcOccupiedEntry {
|
||||
key: None,
|
||||
elem: bucket,
|
||||
table: self.table,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> IterMut<'_, K, V> {
|
||||
/// Returns a iterator of references over the remaining items.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn rustc_iter(&self) -> Iter<'_, K, V> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> IntoIter<K, V> {
|
||||
/// Returns a iterator of references over the remaining items.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn rustc_iter(&self) -> Iter<'_, K, V> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Drain<'_, K, V> {
|
||||
/// Returns a iterator of references over the remaining items.
|
||||
#[cfg_attr(feature = "inline-more", inline)]
|
||||
pub fn rustc_iter(&self) -> Iter<'_, K, V> {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
72
third_party/crates/hashbrown-0.14.5/src/scopeguard.rs
vendored
Normal file
72
third_party/crates/hashbrown-0.14.5/src/scopeguard.rs
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Extracted from the scopeguard crate
|
||||
use core::{
|
||||
mem::ManuallyDrop,
|
||||
ops::{Deref, DerefMut},
|
||||
ptr,
|
||||
};
|
||||
|
||||
pub struct ScopeGuard<T, F>
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
dropfn: F,
|
||||
value: T,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn guard<T, F>(value: T, dropfn: F) -> ScopeGuard<T, F>
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
ScopeGuard { dropfn, value }
|
||||
}
|
||||
|
||||
impl<T, F> ScopeGuard<T, F>
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
#[inline]
|
||||
pub fn into_inner(guard: Self) -> T {
|
||||
// Cannot move out of Drop-implementing types, so
|
||||
// ptr::read the value out of a ManuallyDrop<Self>
|
||||
// Don't use mem::forget as that might invalidate value
|
||||
let guard = ManuallyDrop::new(guard);
|
||||
unsafe {
|
||||
let value = ptr::read(&guard.value);
|
||||
// read the closure so that it is dropped
|
||||
let _ = ptr::read(&guard.dropfn);
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F> Deref for ScopeGuard<T, F>
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
type Target = T;
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F> DerefMut for ScopeGuard<T, F>
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F> Drop for ScopeGuard<T, F>
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
(self.dropfn)(&mut self.value);
|
||||
}
|
||||
}
|
||||
2970
third_party/crates/hashbrown-0.14.5/src/set.rs
vendored
Normal file
2970
third_party/crates/hashbrown-0.14.5/src/set.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2070
third_party/crates/hashbrown-0.14.5/src/table.rs
vendored
Normal file
2070
third_party/crates/hashbrown-0.14.5/src/table.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
53
third_party/crates/hashbrown-0.14.5/tests/equivalent_trait.rs
vendored
Normal file
53
third_party/crates/hashbrown-0.14.5/tests/equivalent_trait.rs
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
use hashbrown::Equivalent;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use std::hash::Hash;
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct Pair<A, B>(pub A, pub B);
|
||||
|
||||
impl<A, B, C, D> PartialEq<(A, B)> for Pair<C, D>
|
||||
where
|
||||
C: PartialEq<A>,
|
||||
D: PartialEq<B>,
|
||||
{
|
||||
fn eq(&self, rhs: &(A, B)) -> bool {
|
||||
self.0 == rhs.0 && self.1 == rhs.1
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, X> Equivalent<X> for Pair<A, B>
|
||||
where
|
||||
Pair<A, B>: PartialEq<X>,
|
||||
A: Hash + Eq,
|
||||
B: Hash + Eq,
|
||||
{
|
||||
fn equivalent(&self, other: &X) -> bool {
|
||||
*self == *other
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lookup() {
|
||||
let s = String::from;
|
||||
let mut map = HashMap::new();
|
||||
map.insert((s("a"), s("b")), 1);
|
||||
map.insert((s("a"), s("x")), 2);
|
||||
|
||||
assert!(map.contains_key(&Pair("a", "b")));
|
||||
assert!(!map.contains_key(&Pair("b", "a")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_str() {
|
||||
let s = String::from;
|
||||
let mut map = HashMap::new();
|
||||
map.insert(s("a"), 1);
|
||||
map.insert(s("b"), 2);
|
||||
map.insert(s("x"), 3);
|
||||
map.insert(s("y"), 4);
|
||||
|
||||
assert!(map.contains_key("a"));
|
||||
assert!(!map.contains_key("z"));
|
||||
assert_eq!(map.remove("b"), Some(2));
|
||||
}
|
||||
65
third_party/crates/hashbrown-0.14.5/tests/hasher.rs
vendored
Normal file
65
third_party/crates/hashbrown-0.14.5/tests/hasher.rs
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
//! Sanity check that alternate hashers work correctly.
|
||||
|
||||
#![cfg(not(miri))] // FIXME: takes too long
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use std::hash::{BuildHasher, BuildHasherDefault, Hasher};
|
||||
|
||||
fn check<S: BuildHasher + Default>() {
|
||||
let range = 0..1_000;
|
||||
|
||||
let mut set = HashSet::<i32, S>::default();
|
||||
set.extend(range.clone());
|
||||
|
||||
assert!(!set.contains(&i32::min_value()));
|
||||
assert!(!set.contains(&(range.start - 1)));
|
||||
for i in range.clone() {
|
||||
assert!(set.contains(&i));
|
||||
}
|
||||
assert!(!set.contains(&range.end));
|
||||
assert!(!set.contains(&i32::max_value()));
|
||||
}
|
||||
|
||||
/// Use hashbrown's default hasher.
|
||||
#[test]
|
||||
fn default() {
|
||||
check::<hashbrown::hash_map::DefaultHashBuilder>();
|
||||
}
|
||||
|
||||
/// Use std's default hasher.
|
||||
#[test]
|
||||
fn random_state() {
|
||||
check::<std::collections::hash_map::RandomState>();
|
||||
}
|
||||
|
||||
/// Use a constant 0 hash.
|
||||
#[test]
|
||||
fn zero() {
|
||||
#[derive(Default)]
|
||||
struct ZeroHasher;
|
||||
|
||||
impl Hasher for ZeroHasher {
|
||||
fn finish(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
fn write(&mut self, _: &[u8]) {}
|
||||
}
|
||||
|
||||
check::<BuildHasherDefault<ZeroHasher>>();
|
||||
}
|
||||
|
||||
/// Use a constant maximum hash.
|
||||
#[test]
|
||||
fn max() {
|
||||
#[derive(Default)]
|
||||
struct MaxHasher;
|
||||
|
||||
impl Hasher for MaxHasher {
|
||||
fn finish(&self) -> u64 {
|
||||
u64::max_value()
|
||||
}
|
||||
fn write(&mut self, _: &[u8]) {}
|
||||
}
|
||||
|
||||
check::<BuildHasherDefault<MaxHasher>>();
|
||||
}
|
||||
11
third_party/crates/hashbrown-0.14.5/tests/raw.rs
vendored
Normal file
11
third_party/crates/hashbrown-0.14.5/tests/raw.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#![cfg(feature = "raw")]
|
||||
|
||||
use hashbrown::raw::RawTable;
|
||||
use std::mem;
|
||||
|
||||
#[test]
|
||||
fn test_allocation_info() {
|
||||
assert_eq!(RawTable::<()>::new().allocation_info().1.size(), 0);
|
||||
assert_eq!(RawTable::<u32>::new().allocation_info().1.size(), 0);
|
||||
assert!(RawTable::<u32>::with_capacity(1).allocation_info().1.size() > mem::size_of::<u32>());
|
||||
}
|
||||
535
third_party/crates/hashbrown-0.14.5/tests/rayon.rs
vendored
Normal file
535
third_party/crates/hashbrown-0.14.5/tests/rayon.rs
vendored
Normal file
@@ -0,0 +1,535 @@
|
||||
#![cfg(feature = "rayon")]
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use rayon::iter::{
|
||||
IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelExtend,
|
||||
ParallelIterator,
|
||||
};
|
||||
|
||||
macro_rules! assert_eq3 {
|
||||
($e1:expr, $e2:expr, $e3:expr) => {{
|
||||
assert_eq!($e1, $e2);
|
||||
assert_eq!($e1, $e3);
|
||||
assert_eq!($e2, $e3);
|
||||
}};
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref MAP_EMPTY: HashMap<char, u32> = HashMap::new();
|
||||
static ref MAP: HashMap<char, u32> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert('b', 20);
|
||||
m.insert('a', 10);
|
||||
m.insert('c', 30);
|
||||
m.insert('e', 50);
|
||||
m.insert('f', 60);
|
||||
m.insert('d', 40);
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_iter_empty() {
|
||||
let vec_seq = MAP_EMPTY.iter().collect::<Vec<_>>();
|
||||
let vec_par = MAP_EMPTY.par_iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_iter() {
|
||||
let mut vec_seq = MAP.iter().collect::<Vec<_>>();
|
||||
let mut vec_par = MAP.par_iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec_seq, vec_par);
|
||||
|
||||
// Do not depend on the exact order of values
|
||||
let expected_sorted = [
|
||||
(&'a', &10),
|
||||
(&'b', &20),
|
||||
(&'c', &30),
|
||||
(&'d', &40),
|
||||
(&'e', &50),
|
||||
(&'f', &60),
|
||||
];
|
||||
|
||||
vec_seq.sort_unstable();
|
||||
vec_par.sort_unstable();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected_sorted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_keys_empty() {
|
||||
let vec_seq = MAP_EMPTY.keys().collect::<Vec<&char>>();
|
||||
let vec_par = MAP_EMPTY.par_keys().collect::<Vec<&char>>();
|
||||
|
||||
let expected: [&char; 0] = [];
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_keys() {
|
||||
let mut vec_seq = MAP.keys().collect::<Vec<_>>();
|
||||
let mut vec_par = MAP.par_keys().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec_seq, vec_par);
|
||||
|
||||
// Do not depend on the exact order of values
|
||||
let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f'];
|
||||
|
||||
vec_seq.sort_unstable();
|
||||
vec_par.sort_unstable();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected_sorted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_values_empty() {
|
||||
let vec_seq = MAP_EMPTY.values().collect::<Vec<_>>();
|
||||
let vec_par = MAP_EMPTY.par_values().collect::<Vec<_>>();
|
||||
|
||||
let expected: [&u32; 0] = [];
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_values() {
|
||||
let mut vec_seq = MAP.values().collect::<Vec<_>>();
|
||||
let mut vec_par = MAP.par_values().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec_seq, vec_par);
|
||||
|
||||
// Do not depend on the exact order of values
|
||||
let expected_sorted = [&10, &20, &30, &40, &50, &60];
|
||||
|
||||
vec_seq.sort_unstable();
|
||||
vec_par.sort_unstable();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected_sorted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_iter_mut_empty() {
|
||||
let mut map1 = MAP_EMPTY.clone();
|
||||
let mut map2 = MAP_EMPTY.clone();
|
||||
|
||||
let vec_seq = map1.iter_mut().collect::<Vec<_>>();
|
||||
let vec_par = map2.par_iter_mut().collect::<Vec<_>>();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_iter_mut() {
|
||||
let mut map1 = MAP.clone();
|
||||
let mut map2 = MAP.clone();
|
||||
|
||||
let mut vec_seq = map1.iter_mut().collect::<Vec<_>>();
|
||||
let mut vec_par = map2.par_iter_mut().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec_seq, vec_par);
|
||||
|
||||
// Do not depend on the exact order of values
|
||||
let expected_sorted = [
|
||||
(&'a', &mut 10),
|
||||
(&'b', &mut 20),
|
||||
(&'c', &mut 30),
|
||||
(&'d', &mut 40),
|
||||
(&'e', &mut 50),
|
||||
(&'f', &mut 60),
|
||||
];
|
||||
|
||||
vec_seq.sort_unstable();
|
||||
vec_par.sort_unstable();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected_sorted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_values_mut_empty() {
|
||||
let mut map1 = MAP_EMPTY.clone();
|
||||
let mut map2 = MAP_EMPTY.clone();
|
||||
|
||||
let vec_seq = map1.values_mut().collect::<Vec<_>>();
|
||||
let vec_par = map2.par_values_mut().collect::<Vec<_>>();
|
||||
|
||||
let expected: [&u32; 0] = [];
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_values_mut() {
|
||||
let mut map1 = MAP.clone();
|
||||
let mut map2 = MAP.clone();
|
||||
|
||||
let mut vec_seq = map1.values_mut().collect::<Vec<_>>();
|
||||
let mut vec_par = map2.par_values_mut().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec_seq, vec_par);
|
||||
|
||||
// Do not depend on the exact order of values
|
||||
let expected_sorted = [&mut 10, &mut 20, &mut 30, &mut 40, &mut 50, &mut 60];
|
||||
|
||||
vec_seq.sort_unstable();
|
||||
vec_par.sort_unstable();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected_sorted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_into_iter_empty() {
|
||||
let vec_seq = MAP_EMPTY.clone().into_iter().collect::<Vec<_>>();
|
||||
let vec_par = MAP_EMPTY.clone().into_par_iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_into_iter() {
|
||||
let mut vec_seq = MAP.clone().into_iter().collect::<Vec<_>>();
|
||||
let mut vec_par = MAP.clone().into_par_iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec_seq, vec_par);
|
||||
|
||||
// Do not depend on the exact order of values
|
||||
let expected_sorted = [
|
||||
('a', 10),
|
||||
('b', 20),
|
||||
('c', 30),
|
||||
('d', 40),
|
||||
('e', 50),
|
||||
('f', 60),
|
||||
];
|
||||
|
||||
vec_seq.sort_unstable();
|
||||
vec_par.sort_unstable();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected_sorted);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref MAP_VEC_EMPTY: Vec<(char, u32)> = vec![];
|
||||
static ref MAP_VEC: Vec<(char, u32)> = vec![
|
||||
('b', 20),
|
||||
('a', 10),
|
||||
('c', 30),
|
||||
('e', 50),
|
||||
('f', 60),
|
||||
('d', 40),
|
||||
];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_collect_empty() {
|
||||
let map_expected = MAP_EMPTY.clone();
|
||||
let map_seq = MAP_VEC_EMPTY.clone().into_iter().collect::<HashMap<_, _>>();
|
||||
let map_par = MAP_VEC_EMPTY
|
||||
.clone()
|
||||
.into_par_iter()
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
assert_eq!(map_seq, map_par);
|
||||
assert_eq!(map_seq, map_expected);
|
||||
assert_eq!(map_par, map_expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_collect() {
|
||||
let map_expected = MAP.clone();
|
||||
let map_seq = MAP_VEC.clone().into_iter().collect::<HashMap<_, _>>();
|
||||
let map_par = MAP_VEC.clone().into_par_iter().collect::<HashMap<_, _>>();
|
||||
|
||||
assert_eq!(map_seq, map_par);
|
||||
assert_eq!(map_seq, map_expected);
|
||||
assert_eq!(map_par, map_expected);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref MAP_EXISTING_EMPTY: HashMap<char, u32> = HashMap::new();
|
||||
static ref MAP_EXISTING: HashMap<char, u32> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert('b', 20);
|
||||
m.insert('a', 10);
|
||||
m
|
||||
};
|
||||
static ref MAP_EXTENSION_EMPTY: Vec<(char, u32)> = vec![];
|
||||
static ref MAP_EXTENSION: Vec<(char, u32)> = vec![('c', 30), ('e', 50), ('f', 60), ('d', 40),];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_existing_empty_extend_empty() {
|
||||
let expected = HashMap::new();
|
||||
let mut map_seq = MAP_EXISTING_EMPTY.clone();
|
||||
let mut map_par = MAP_EXISTING_EMPTY.clone();
|
||||
|
||||
map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied());
|
||||
map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied());
|
||||
|
||||
assert_eq3!(map_seq, map_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_existing_empty_extend() {
|
||||
let expected = MAP_EXTENSION.iter().copied().collect::<HashMap<_, _>>();
|
||||
let mut map_seq = MAP_EXISTING_EMPTY.clone();
|
||||
let mut map_par = MAP_EXISTING_EMPTY.clone();
|
||||
|
||||
map_seq.extend(MAP_EXTENSION.iter().copied());
|
||||
map_par.par_extend(MAP_EXTENSION.par_iter().copied());
|
||||
|
||||
assert_eq3!(map_seq, map_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_existing_extend_empty() {
|
||||
let expected = MAP_EXISTING.clone();
|
||||
let mut map_seq = MAP_EXISTING.clone();
|
||||
let mut map_par = MAP_EXISTING.clone();
|
||||
|
||||
map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied());
|
||||
map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied());
|
||||
|
||||
assert_eq3!(map_seq, map_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_seq_par_equivalence_existing_extend() {
|
||||
let expected = MAP.clone();
|
||||
let mut map_seq = MAP_EXISTING.clone();
|
||||
let mut map_par = MAP_EXISTING.clone();
|
||||
|
||||
map_seq.extend(MAP_EXTENSION.iter().copied());
|
||||
map_par.par_extend(MAP_EXTENSION.par_iter().copied());
|
||||
|
||||
assert_eq3!(map_seq, map_par, expected);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SET_EMPTY: HashSet<char> = HashSet::new();
|
||||
static ref SET: HashSet<char> = {
|
||||
let mut s = HashSet::new();
|
||||
s.insert('b');
|
||||
s.insert('a');
|
||||
s.insert('c');
|
||||
s.insert('e');
|
||||
s.insert('f');
|
||||
s.insert('d');
|
||||
s
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_iter_empty() {
|
||||
let vec_seq = SET_EMPTY.iter().collect::<Vec<_>>();
|
||||
let vec_par = SET_EMPTY.par_iter().collect::<Vec<_>>();
|
||||
|
||||
let expected: [&char; 0] = [];
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_iter() {
|
||||
let mut vec_seq = SET.iter().collect::<Vec<_>>();
|
||||
let mut vec_par = SET.par_iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec_seq, vec_par);
|
||||
|
||||
// Do not depend on the exact order of values
|
||||
let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f'];
|
||||
|
||||
vec_seq.sort_unstable();
|
||||
vec_par.sort_unstable();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected_sorted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_into_iter_empty() {
|
||||
let vec_seq = SET_EMPTY.clone().into_iter().collect::<Vec<_>>();
|
||||
let vec_par = SET_EMPTY.clone().into_par_iter().collect::<Vec<_>>();
|
||||
|
||||
// Work around type inference failure introduced by rend dev-dependency.
|
||||
let empty: [char; 0] = [];
|
||||
assert_eq3!(vec_seq, vec_par, empty);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_into_iter() {
|
||||
let mut vec_seq = SET.clone().into_iter().collect::<Vec<_>>();
|
||||
let mut vec_par = SET.clone().into_par_iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(vec_seq, vec_par);
|
||||
|
||||
// Do not depend on the exact order of values
|
||||
let expected_sorted = ['a', 'b', 'c', 'd', 'e', 'f'];
|
||||
|
||||
vec_seq.sort_unstable();
|
||||
vec_par.sort_unstable();
|
||||
|
||||
assert_eq3!(vec_seq, vec_par, expected_sorted);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SET_VEC_EMPTY: Vec<char> = vec![];
|
||||
static ref SET_VEC: Vec<char> = vec!['b', 'a', 'c', 'e', 'f', 'd',];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_collect_empty() {
|
||||
let set_expected = SET_EMPTY.clone();
|
||||
let set_seq = SET_VEC_EMPTY.clone().into_iter().collect::<HashSet<_>>();
|
||||
let set_par = SET_VEC_EMPTY
|
||||
.clone()
|
||||
.into_par_iter()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq!(set_seq, set_par);
|
||||
assert_eq!(set_seq, set_expected);
|
||||
assert_eq!(set_par, set_expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_collect() {
|
||||
let set_expected = SET.clone();
|
||||
let set_seq = SET_VEC.clone().into_iter().collect::<HashSet<_>>();
|
||||
let set_par = SET_VEC.clone().into_par_iter().collect::<HashSet<_>>();
|
||||
|
||||
assert_eq!(set_seq, set_par);
|
||||
assert_eq!(set_seq, set_expected);
|
||||
assert_eq!(set_par, set_expected);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SET_EXISTING_EMPTY: HashSet<char> = HashSet::new();
|
||||
static ref SET_EXISTING: HashSet<char> = {
|
||||
let mut s = HashSet::new();
|
||||
s.insert('b');
|
||||
s.insert('a');
|
||||
s
|
||||
};
|
||||
static ref SET_EXTENSION_EMPTY: Vec<char> = vec![];
|
||||
static ref SET_EXTENSION: Vec<char> = vec!['c', 'e', 'f', 'd',];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_existing_empty_extend_empty() {
|
||||
let expected = HashSet::new();
|
||||
let mut set_seq = SET_EXISTING_EMPTY.clone();
|
||||
let mut set_par = SET_EXISTING_EMPTY.clone();
|
||||
|
||||
set_seq.extend(SET_EXTENSION_EMPTY.iter().copied());
|
||||
set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied());
|
||||
|
||||
assert_eq3!(set_seq, set_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_existing_empty_extend() {
|
||||
let expected = SET_EXTENSION.iter().copied().collect::<HashSet<_>>();
|
||||
let mut set_seq = SET_EXISTING_EMPTY.clone();
|
||||
let mut set_par = SET_EXISTING_EMPTY.clone();
|
||||
|
||||
set_seq.extend(SET_EXTENSION.iter().copied());
|
||||
set_par.par_extend(SET_EXTENSION.par_iter().copied());
|
||||
|
||||
assert_eq3!(set_seq, set_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_existing_extend_empty() {
|
||||
let expected = SET_EXISTING.clone();
|
||||
let mut set_seq = SET_EXISTING.clone();
|
||||
let mut set_par = SET_EXISTING.clone();
|
||||
|
||||
set_seq.extend(SET_EXTENSION_EMPTY.iter().copied());
|
||||
set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied());
|
||||
|
||||
assert_eq3!(set_seq, set_par, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_existing_extend() {
|
||||
let expected = SET.clone();
|
||||
let mut set_seq = SET_EXISTING.clone();
|
||||
let mut set_par = SET_EXISTING.clone();
|
||||
|
||||
set_seq.extend(SET_EXTENSION.iter().copied());
|
||||
set_par.par_extend(SET_EXTENSION.par_iter().copied());
|
||||
|
||||
assert_eq3!(set_seq, set_par, expected);
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SET_A: HashSet<char> = ['a', 'b', 'c', 'd'].iter().copied().collect();
|
||||
static ref SET_B: HashSet<char> = ['a', 'b', 'e', 'f'].iter().copied().collect();
|
||||
static ref SET_DIFF_AB: HashSet<char> = ['c', 'd'].iter().copied().collect();
|
||||
static ref SET_DIFF_BA: HashSet<char> = ['e', 'f'].iter().copied().collect();
|
||||
static ref SET_SYMM_DIFF_AB: HashSet<char> = ['c', 'd', 'e', 'f'].iter().copied().collect();
|
||||
static ref SET_INTERSECTION_AB: HashSet<char> = ['a', 'b'].iter().copied().collect();
|
||||
static ref SET_UNION_AB: HashSet<char> =
|
||||
['a', 'b', 'c', 'd', 'e', 'f'].iter().copied().collect();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_difference() {
|
||||
let diff_ab_seq = SET_A.difference(&*SET_B).copied().collect::<HashSet<_>>();
|
||||
let diff_ab_par = SET_A
|
||||
.par_difference(&*SET_B)
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(diff_ab_seq, diff_ab_par, *SET_DIFF_AB);
|
||||
|
||||
let diff_ba_seq = SET_B.difference(&*SET_A).copied().collect::<HashSet<_>>();
|
||||
let diff_ba_par = SET_B
|
||||
.par_difference(&*SET_A)
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(diff_ba_seq, diff_ba_par, *SET_DIFF_BA);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_symmetric_difference() {
|
||||
let symm_diff_ab_seq = SET_A
|
||||
.symmetric_difference(&*SET_B)
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
let symm_diff_ab_par = SET_A
|
||||
.par_symmetric_difference(&*SET_B)
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(symm_diff_ab_seq, symm_diff_ab_par, *SET_SYMM_DIFF_AB);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_intersection() {
|
||||
let intersection_ab_seq = SET_A.intersection(&*SET_B).copied().collect::<HashSet<_>>();
|
||||
let intersection_ab_par = SET_A
|
||||
.par_intersection(&*SET_B)
|
||||
.copied()
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(
|
||||
intersection_ab_seq,
|
||||
intersection_ab_par,
|
||||
*SET_INTERSECTION_AB
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_seq_par_equivalence_union() {
|
||||
let union_ab_seq = SET_A.union(&*SET_B).copied().collect::<HashSet<_>>();
|
||||
let union_ab_par = SET_A.par_union(&*SET_B).copied().collect::<HashSet<_>>();
|
||||
|
||||
assert_eq3!(union_ab_seq, union_ab_par, *SET_UNION_AB);
|
||||
}
|
||||
65
third_party/crates/hashbrown-0.14.5/tests/serde.rs
vendored
Normal file
65
third_party/crates/hashbrown-0.14.5/tests/serde.rs
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
#![cfg(feature = "serde")]
|
||||
|
||||
use core::hash::BuildHasherDefault;
|
||||
use fnv::FnvHasher;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use serde_test::{assert_tokens, Token};
|
||||
|
||||
// We use FnvHash for this test because we rely on the ordering
|
||||
type FnvHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FnvHasher>>;
|
||||
type FnvHashSet<T> = HashSet<T, BuildHasherDefault<FnvHasher>>;
|
||||
|
||||
#[test]
|
||||
fn map_serde_tokens_empty() {
|
||||
let map = FnvHashMap::<char, u32>::default();
|
||||
|
||||
assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_serde_tokens() {
|
||||
let mut map = FnvHashMap::default();
|
||||
map.insert('b', 20);
|
||||
map.insert('a', 10);
|
||||
map.insert('c', 30);
|
||||
|
||||
assert_tokens(
|
||||
&map,
|
||||
&[
|
||||
Token::Map { len: Some(3) },
|
||||
Token::Char('a'),
|
||||
Token::I32(10),
|
||||
Token::Char('c'),
|
||||
Token::I32(30),
|
||||
Token::Char('b'),
|
||||
Token::I32(20),
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_serde_tokens_empty() {
|
||||
let set = FnvHashSet::<u32>::default();
|
||||
|
||||
assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_serde_tokens() {
|
||||
let mut set = FnvHashSet::default();
|
||||
set.insert(20);
|
||||
set.insert(10);
|
||||
set.insert(30);
|
||||
|
||||
assert_tokens(
|
||||
&set,
|
||||
&[
|
||||
Token::Seq { len: Some(3) },
|
||||
Token::I32(30),
|
||||
Token::I32(20),
|
||||
Token::I32(10),
|
||||
Token::SeqEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
34
third_party/crates/hashbrown-0.14.5/tests/set.rs
vendored
Normal file
34
third_party/crates/hashbrown-0.14.5/tests/set.rs
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
#![cfg(not(miri))] // FIXME: takes too long
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng};
|
||||
use std::iter;
|
||||
|
||||
#[test]
|
||||
fn test_hashset_insert_remove() {
|
||||
let mut m: HashSet<Vec<char>> = HashSet::new();
|
||||
let seed = u64::from_le_bytes(*b"testseed");
|
||||
|
||||
let rng = &mut SmallRng::seed_from_u64(seed);
|
||||
let tx: Vec<Vec<char>> = iter::repeat_with(|| {
|
||||
rng.sample_iter(&Alphanumeric)
|
||||
.take(32)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
})
|
||||
.take(4096)
|
||||
.collect();
|
||||
|
||||
// more readable with explicit `true` / `false`
|
||||
#[allow(clippy::bool_assert_comparison)]
|
||||
for _ in 0..32 {
|
||||
for x in &tx {
|
||||
assert_eq!(m.contains(x), false);
|
||||
assert_eq!(m.insert(x.clone()), true);
|
||||
}
|
||||
for (i, x) in tx.iter().enumerate() {
|
||||
println!("removing {i} {x:?}");
|
||||
assert_eq!(m.remove(x), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
third_party/crates/rnix-0.14.0/.cargo-checksum.json
vendored
Normal file
1
third_party/crates/rnix-0.14.0/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
7
third_party/crates/rnix-0.14.0/.cargo_vcs_info.json
vendored
Normal file
7
third_party/crates/rnix-0.14.0/.cargo_vcs_info.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"git": {
|
||||
"sha1": "0472081214c24b1ab4d34f7bf544284ed4e45ad3",
|
||||
"dirty": true
|
||||
},
|
||||
"path_in_vcs": ""
|
||||
}
|
||||
36
third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
36
third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
Feel free to remove paragraphs that don't apply to your bugreport.
|
||||
-->
|
||||
|
||||
### Describe the bug
|
||||
|
||||
<!-- A clear and concise description of what the bug is.-->
|
||||
|
||||
### Code Snippet to reproduce
|
||||
|
||||
<!--
|
||||
If applicable, a Nix expression that demonstrates the problem.
|
||||
-->
|
||||
|
||||
```nix
|
||||
|
||||
```
|
||||
|
||||
### Expected behavior
|
||||
|
||||
<!-- A clear and concise description of what you expected to happen.-->
|
||||
|
||||
### Additional context
|
||||
|
||||
<!--
|
||||
Anything else you consider relevant such as `rnix` version (mandatory), related issues etc.
|
||||
-->
|
||||
|
||||
29
third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
29
third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
Feel free to remove paragraphs that don't apply to your request.
|
||||
-->
|
||||
|
||||
### Description
|
||||
|
||||
<!--
|
||||
Describe the feature / a possible solution you'd like to see.
|
||||
-->
|
||||
|
||||
### Considered alternatives
|
||||
|
||||
<!--
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
-->
|
||||
|
||||
### Additional context
|
||||
|
||||
<!--
|
||||
Add any context such as screenshots, related issues or whatever you consider relevant here.
|
||||
-->
|
||||
7
third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
7
third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a general question about the project
|
||||
title: ''
|
||||
labels: 'question'
|
||||
assignees: ''
|
||||
---
|
||||
25
third_party/crates/rnix-0.14.0/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
25
third_party/crates/rnix-0.14.0/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
<!--
|
||||
Feel free to remove paragraphs that don't apply to your PR.
|
||||
-->
|
||||
|
||||
### Summary & Motivation
|
||||
|
||||
<!--
|
||||
Please summarize the changes you've made and the motivation behind it.
|
||||
-->
|
||||
|
||||
### Backwards-incompatible changes
|
||||
|
||||
<!--
|
||||
If applicable, please summarize which changes of your PR are backwards-incompatible
|
||||
to the latest release.
|
||||
-->
|
||||
|
||||
### Further context
|
||||
|
||||
<!--
|
||||
If applicable, please give further context such as related issues / PRs,
|
||||
an explanation of the problem you're aiming to solve or anything else you also
|
||||
consider relevant.
|
||||
-->
|
||||
6
third_party/crates/rnix-0.14.0/.github/dependabot.yml
vendored
Normal file
6
third_party/crates/rnix-0.14.0/.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
64
third_party/crates/rnix-0.14.0/.github/workflows/ci.yml
vendored
Normal file
64
third_party/crates/rnix-0.14.0/.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: ci
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: test
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Cache Dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Compile
|
||||
run: cargo test --no-run --locked
|
||||
|
||||
- name: Test
|
||||
run: cargo test -- --nocapture
|
||||
|
||||
rustfmt:
|
||||
name: rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
clippy:
|
||||
name: clippy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy
|
||||
|
||||
- name: Run Clippy
|
||||
run: cargo clippy
|
||||
113
third_party/crates/rnix-0.14.0/BUILD.bazel
vendored
Normal file
113
third_party/crates/rnix-0.14.0/BUILD.bazel
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
###############################################################################
|
||||
# @generated
|
||||
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
|
||||
# regenerate this file, run the following:
|
||||
#
|
||||
# bazel run @@//third_party:vendor_crates
|
||||
###############################################################################
|
||||
|
||||
load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars")
|
||||
load("@rules_rust//rust:defs.bzl", "rust_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cargo_toml_env_vars(
|
||||
name = "cargo_toml_env_vars",
|
||||
src = "Cargo.toml",
|
||||
)
|
||||
|
||||
rust_library(
|
||||
name = "rnix",
|
||||
srcs = glob(
|
||||
include = ["**/*.rs"],
|
||||
allow_empty = False,
|
||||
),
|
||||
compile_data = glob(
|
||||
include = ["**"],
|
||||
allow_empty = True,
|
||||
exclude = [
|
||||
"**/* *",
|
||||
".tmp_git_root/**/*",
|
||||
"BUILD",
|
||||
"BUILD.bazel",
|
||||
"WORKSPACE",
|
||||
"WORKSPACE.bazel",
|
||||
],
|
||||
),
|
||||
crate_root = "src/lib.rs",
|
||||
edition = "2021",
|
||||
rustc_env_files = [
|
||||
":cargo_toml_env_vars",
|
||||
],
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-bazel",
|
||||
"crate-name=rnix",
|
||||
"manual",
|
||||
"noclippy",
|
||||
"norustfmt",
|
||||
],
|
||||
target_compatible_with = select({
|
||||
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios-macabi": [],
|
||||
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
|
||||
"@rules_rust//rust/platform:aarch64-linux-android": [],
|
||||
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-fuchsia": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-none": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
|
||||
"@rules_rust//rust/platform:aarch64-unknown-uefi": [],
|
||||
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
|
||||
"@rules_rust//rust/platform:arm-unknown-linux-musleabi": [],
|
||||
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
|
||||
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
|
||||
"@rules_rust//rust/platform:i686-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:i686-linux-android": [],
|
||||
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
|
||||
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:mips-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
|
||||
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-netbsd": [],
|
||||
"@rules_rust//rust/platform:sparc64-unknown-openbsd": [],
|
||||
"@rules_rust//rust/platform:thumbv6m-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv7em-none-eabihf": [],
|
||||
"@rules_rust//rust/platform:thumbv7m-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
|
||||
"@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [],
|
||||
"@rules_rust//rust/platform:wasm32-unknown-emscripten": [],
|
||||
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip1": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip1-threads": [],
|
||||
"@rules_rust//rust/platform:wasm32-wasip2": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-ios": [],
|
||||
"@rules_rust//rust/platform:x86_64-apple-ios-macabi": [],
|
||||
"@rules_rust//rust/platform:x86_64-linux-android": [],
|
||||
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-fuchsia": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-none": [],
|
||||
"@rules_rust//rust/platform:x86_64-unknown-uefi": [],
|
||||
"//conditions:default": ["@platforms//:incompatible"],
|
||||
}),
|
||||
version = "0.14.0",
|
||||
deps = [
|
||||
"//third_party/crates/rowan-0.16.1:rowan",
|
||||
],
|
||||
)
|
||||
190
third_party/crates/rnix-0.14.0/CHANGELOG.md
vendored
Normal file
190
third_party/crates/rnix-0.14.0/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes between releases will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.14.0] - 2026-02-16
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fix absolute path interpolation starting with `/${` failing to parse
|
||||
([#182](https://github.com/nix-community/rnix-parser/issues/182),
|
||||
from [@imxyy1soope1](https://github.com/imxyy1soope1)).
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* **`__curPos` is now a distinct node type.** `__curPos` is a Nix keyword that evaluates to an
|
||||
attribute set containing the file, line, and column where it appears.
|
||||
[Lix documents this as a keyword.](https://docs.lix.systems/manual/lix/nightly/language/constructs.html#keywords-__curPos)
|
||||
It was previously represented as `NODE_IDENT`, but is now parsed as `NODE_CUR_POS` with a
|
||||
corresponding `TOKEN_CUR_POS` token kind (from [@3timeslazy](https://github.com/3timeslazy)).
|
||||
|
||||
## [v0.13.0] - 2026-01-29
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* **Path types are now distinguished at the type level.** `TOKEN_PATH` and `NODE_PATH` have been
|
||||
replaced with specific variants for each path type:
|
||||
- `TOKEN_PATH_ABS` / `NODE_PATH_ABS` - absolute paths (`/foo/bar`)
|
||||
- `TOKEN_PATH_REL` / `NODE_PATH_REL` - relative paths (`./foo`, `../bar`, `foo/bar`)
|
||||
- `TOKEN_PATH_HOME` / `NODE_PATH_HOME` - home-relative paths (`~/foo`)
|
||||
- `TOKEN_PATH_SEARCH` / `NODE_PATH_SEARCH` - search paths (`<nixpkgs>`)
|
||||
|
||||
The `ast::Expr` enum now has `PathAbs`, `PathRel`, `PathHome`, and `PathSearch` variants
|
||||
instead of a single `Path` variant. See `MIGRATING.md` for upgrade guidance.
|
||||
|
||||
* **Double slashes in paths are now syntax errors.** Paths like `foo//bar` now produce
|
||||
`TOKEN_ERROR` instead of being parsed.
|
||||
|
||||
* **The `parser` and `tokenizer` modules are now private.** Use `rnix::Root::parse()` and
|
||||
`rnix::tokenize()` instead.
|
||||
|
||||
### Added
|
||||
|
||||
* Implement `FromStr` for `SyntaxKind` (from [@abhillman](https://github.com/abhillman)).
|
||||
|
||||
* Add `MIGRATING.md` with upgrade guidance for breaking changes.
|
||||
|
||||
* Add `nix develop .#fuzz` devShell for running cargo-fuzz with nightly Rust.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fix leading zero number parsing to match Nix behavior (from [@hsjobeki](https://github.com/hsjobeki)).
|
||||
|
||||
### Changed
|
||||
|
||||
* Update `rowan` to 0.16.
|
||||
* Update `criterion` to 0.8.
|
||||
* Update `expect-test` to 1.5.1.
|
||||
* Add Clippy to CI and resolve all warnings.
|
||||
|
||||
## [v0.12.0] - 2025-01-09
|
||||
|
||||
* Add support for pipe operators
|
||||
|
||||
## [v0.11.0] - 2022-11-11
|
||||
|
||||
* removes the `types` module and replaces it with `ast`
|
||||
|
||||
* the `ast` modules has better types and sum types
|
||||
|
||||
* removes `ParsedType` in favor of `Expr`
|
||||
|
||||
* removes the `value` module. methods on `Value` go on the individual types. For example, string related methods go on `ast::Str`
|
||||
|
||||
* `parse` changed to `Root::parse`
|
||||
|
||||
* `NODE_OR_DEFAULT` is removed
|
||||
|
||||
* `NODE_KEY` -> `NODE_ATTRPATH`, `NODE_KEY_VALUE` -> `NODE_ATTRPATH_VALUE`
|
||||
|
||||
* `BinOp::IsSet` is removed since it's actually not a normal binary operator.
|
||||
|
||||
* `NODE_SELECT` is flattened in favor of `NODE_ATTRPATH` which consists of multiple Attrs, including `a.b.c` and `a.b.c or expr`
|
||||
|
||||
* `a or b` is Apply, not "OrDefault", which matches the result of Nix. Fixes #23
|
||||
|
||||
* `${` is considered invalid at Expr places now, which matches the result of Nix.
|
||||
|
||||
* remove `TOKEN_DYNAMIC_START` and `TOKEN_DYNAMIC_END`
|
||||
|
||||
* rowan 15.0
|
||||
|
||||
* various other parsing fixes
|
||||
|
||||
## [v0.10.2] - 2022-06-14
|
||||
|
||||
* Correctly parse every possible case of path-interpolation in Nix code ([#85](https://github.com/nix-community/rnix-parser/issues/85)).
|
||||
|
||||
(from [@ncfavier](https://github.com/ncfavier)).
|
||||
|
||||
## [v0.10.1] - 2021-12-06
|
||||
|
||||
### Fixed
|
||||
|
||||
* Trivia tokens (i.e. ` `, `\r`, `\n` etc.) are no longer misplaced around path-expressions.
|
||||
This is a regression from `v0.10.0` which would've broken `nixpkgs-fmt`.
|
||||
|
||||
(from [@Ma27](https://github.com/Ma27)).
|
||||
|
||||
## [v0.10.0] - 2021-11-30
|
||||
|
||||
### Added
|
||||
|
||||
* Support for the new path-interpolation syntax from Nix 2.4 was added. The parser
|
||||
now correctly detects
|
||||
|
||||
```nix
|
||||
./foo/${bar}
|
||||
```
|
||||
|
||||
as valid code and parses it down to
|
||||
|
||||
```
|
||||
NODE_ROOT 0..13 {
|
||||
NODE_PATH_WITH_INTERPOL 0..12 {
|
||||
TOKEN_PATH("./foo/") 0..6
|
||||
NODE_STRING_INTERPOL 6..12 {
|
||||
TOKEN_INTERPOL_START("${") 6..8
|
||||
NODE_IDENT 8..11 {
|
||||
TOKEN_IDENT("bar") 8..11
|
||||
}
|
||||
TOKEN_INTERPOL_END("}") 11..12
|
||||
}
|
||||
}
|
||||
TOKEN_WHITESPACE("\n") 12..13
|
||||
}
|
||||
```
|
||||
|
||||
Paths without interpolation are still within `NODE_LITERAL` for backwards-compatibility.
|
||||
|
||||
(from [@Ma27](https://github.com/Ma27)).
|
||||
|
||||
* `rnix::types::ParsedTypeError` now implements the `Debug`, `Copy`, `Clone`, `fmt::Display` traits (from [@NerdyPepper](https://github.com/NerdyPepper)).
|
||||
|
||||
* During development, the parser can be tested like this:
|
||||
|
||||
```
|
||||
$ cargo run --example from-stdin <<< 'builtins.map (x: x * x) [ 1 2 3 ]'
|
||||
```
|
||||
|
||||
(from [@efx](https://github.com/efx)).
|
||||
|
||||
### Changed
|
||||
|
||||
* A few more examples of invalid `inherit`-expressions are correctly marked as such (from [@oberblastmeister](https://github.com/oberblastmeister)).
|
||||
|
||||
* `rnix::types::BinOp::operator()` now returns `Option<BinOpKind>` rather than unwrapping the
|
||||
value (from [@NerdyPepper](https://github.com/NerdyPepper)).
|
||||
|
||||
If your code worked fine before, it will be sufficient to add a `.unwrap()` since this was
|
||||
what happened before within `::operator()`.
|
||||
|
||||
* Duplicated arguments in the argument-pattern syntax are now marked as parser error. E.g.
|
||||
|
||||
```nix
|
||||
{ a, a }: a
|
||||
```
|
||||
|
||||
now produces an error (from [@Ma27](https://github.com/Ma27)).
|
||||
|
||||
* Floats without trailing zeroes (e.g. `.5`) are no longer marked as syntax error (from [@Ma27](https://github.com/Ma27)).
|
||||
|
||||
## [v0.9.1] - 2021-09-23
|
||||
|
||||
### Changed
|
||||
|
||||
* Fixed a memory leak while parsing `inherit`-expressions with invalid syntax (from [@Ma27](https://github.com/Ma27/)).
|
||||
|
||||
[Unreleased]: https://github.com/nix-community/rnix-parser/compare/v0.14.0...master
|
||||
[v0.14.0]: https://github.com/nix-community/rnix-parser/compare/v0.13.0...v0.14.0
|
||||
[v0.13.0]: https://github.com/nix-community/rnix-parser/compare/v0.12.0...v0.13.0
|
||||
[v0.12.0]: https://github.com/nix-community/rnix-parser/compare/v0.11.0...v0.12.0
|
||||
[v0.11.0]: https://github.com/nix-community/rnix-parser/compare/v0.10.2...v0.11.0
|
||||
[v0.10.2]: https://github.com/nix-community/rnix-parser/compare/v0.10.1...v0.10.2
|
||||
[v0.10.1]: https://github.com/nix-community/rnix-parser/compare/v0.10.0...v0.10.1
|
||||
[v0.10.0]: https://github.com/nix-community/rnix-parser/compare/v0.9.1...v0.10.0
|
||||
[v0.9.1]: https://github.com/nix-community/rnix-parser/compare/v0.9.0...v0.9.1
|
||||
660
third_party/crates/rnix-0.14.0/Cargo.lock
generated
vendored
Normal file
660
third_party/crates/rnix-0.14.0/Cargo.lock
generated
vendored
Normal file
@@ -0,0 +1,660 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloca"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anes"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"ciborium-ll",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-io"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-ll"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e34525d5bbbd55da2bb745d34b36121baac88d07619a9a09cfcf4a6c0832785"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59a20016a20a3da95bef50ec7238dbd09baeef4311dcdd38ec15aba69812fb61"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
||||
|
||||
[[package]]
|
||||
name = "countme"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d883447757bb0ee46f233e9dc22eb84d93a9508c9b868687b274fc431d886bf"
|
||||
dependencies = [
|
||||
"alloca",
|
||||
"anes",
|
||||
"cast",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"itertools",
|
||||
"num-traits",
|
||||
"oorandom",
|
||||
"page_size",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed943f81ea2faa8dcecbbfa50164acf95d555afec96a27871663b300e387b2e4"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
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-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "dissimilar"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "expect-test"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0"
|
||||
dependencies = [
|
||||
"dissimilar",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.180"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
|
||||
|
||||
[[package]]
|
||||
name = "page_size"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
"plotters-svg",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters-backend"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
|
||||
|
||||
[[package]]
|
||||
name = "plotters-svg"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
|
||||
dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "rnix"
|
||||
version = "0.14.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"expect-test",
|
||||
"rowan",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rowan"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21"
|
||||
dependencies = [
|
||||
"countme",
|
||||
"hashbrown",
|
||||
"rustc-hash",
|
||||
"text-size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "text-size"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[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.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[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-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439"
|
||||
68
third_party/crates/rnix-0.14.0/Cargo.toml
vendored
Normal file
68
third_party/crates/rnix-0.14.0/Cargo.toml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# 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 = "rnix"
|
||||
version = "0.14.0"
|
||||
authors = ["jD91mZM2 <me@krake.one>"]
|
||||
build = false
|
||||
autolib = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "A Nix parser written in Rust"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/nix-community/rnix-parser"
|
||||
|
||||
[lib]
|
||||
name = "rnix"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[example]]
|
||||
name = "dump-ast"
|
||||
path = "examples/dump-ast.rs"
|
||||
|
||||
[[example]]
|
||||
name = "error-report"
|
||||
path = "examples/error-report.rs"
|
||||
|
||||
[[example]]
|
||||
name = "from-stdin"
|
||||
path = "examples/from-stdin.rs"
|
||||
|
||||
[[example]]
|
||||
name = "list-fns"
|
||||
path = "examples/list-fns.rs"
|
||||
|
||||
[[example]]
|
||||
name = "preserve"
|
||||
path = "examples/preserve.rs"
|
||||
|
||||
[[example]]
|
||||
name = "test-nixpkgs"
|
||||
path = "examples/test-nixpkgs.rs"
|
||||
|
||||
[[bench]]
|
||||
name = "all-packages"
|
||||
path = "benches/all-packages.rs"
|
||||
harness = false
|
||||
|
||||
[dependencies.rowan]
|
||||
version = "0.16"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.8"
|
||||
|
||||
[dev-dependencies.expect-test]
|
||||
version = "1.5.1"
|
||||
20
third_party/crates/rnix-0.14.0/Cargo.toml.orig
generated
vendored
Normal file
20
third_party/crates/rnix-0.14.0/Cargo.toml.orig
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
authors = ["jD91mZM2 <me@krake.one>"]
|
||||
description = "A Nix parser written in Rust"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "rnix"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/nix-community/rnix-parser"
|
||||
version = "0.14.0"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "all-packages"
|
||||
|
||||
[dependencies]
|
||||
rowan = "0.16"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.8"
|
||||
expect-test = "1.5.1"
|
||||
21
third_party/crates/rnix-0.14.0/LICENSE
vendored
Normal file
21
third_party/crates/rnix-0.14.0/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 jD91mZM2
|
||||
|
||||
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.
|
||||
104
third_party/crates/rnix-0.14.0/MIGRATING.md
vendored
Normal file
104
third_party/crates/rnix-0.14.0/MIGRATING.md
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
# Migration Guide
|
||||
|
||||
## Migrating to 0.13.0
|
||||
|
||||
### Path types are now distinguished at the type level
|
||||
|
||||
Previously, all Nix paths were parsed into a single `TOKEN_PATH` / `NODE_PATH` type, requiring runtime string inspection to determine the path variant. Now, paths are distinguished at the type level:
|
||||
|
||||
| Path Type | Example | Token | Node |
|
||||
|-----------|---------|-------|------|
|
||||
| Absolute | `/foo/bar` | `TOKEN_PATH_ABS` | `NODE_PATH_ABS` |
|
||||
| Relative | `./foo`, `../bar`, `foo/bar` | `TOKEN_PATH_REL` | `NODE_PATH_REL` |
|
||||
| Home-relative | `~/foo` | `TOKEN_PATH_HOME` | `NODE_PATH_HOME` |
|
||||
| Search | `<nixpkgs>` | `TOKEN_PATH_SEARCH` | `NODE_PATH_SEARCH` |
|
||||
|
||||
#### Updating `SyntaxKind` matches
|
||||
|
||||
```rust
|
||||
// Before:
|
||||
match kind {
|
||||
SyntaxKind::TOKEN_PATH => { /* ... */ }
|
||||
SyntaxKind::NODE_PATH => { /* ... */ }
|
||||
}
|
||||
|
||||
// After:
|
||||
match kind {
|
||||
SyntaxKind::TOKEN_PATH_ABS
|
||||
| SyntaxKind::TOKEN_PATH_REL
|
||||
| SyntaxKind::TOKEN_PATH_HOME
|
||||
| SyntaxKind::TOKEN_PATH_SEARCH => { /* ... */ }
|
||||
|
||||
SyntaxKind::NODE_PATH_ABS
|
||||
| SyntaxKind::NODE_PATH_REL
|
||||
| SyntaxKind::NODE_PATH_HOME
|
||||
| SyntaxKind::NODE_PATH_SEARCH => { /* ... */ }
|
||||
}
|
||||
```
|
||||
|
||||
#### Updating `Expr` matches
|
||||
|
||||
The `Expr` enum no longer has a `Path` variant. Instead, there are four separate variants:
|
||||
|
||||
```rust
|
||||
// Before:
|
||||
match expr {
|
||||
ast::Expr::Path(p) => {
|
||||
// Had to inspect the string to determine path type
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
// After:
|
||||
match expr {
|
||||
ast::Expr::PathAbs(p) => { /* absolute path like /foo/bar */ }
|
||||
ast::Expr::PathRel(p) => { /* relative path like ./foo */ }
|
||||
ast::Expr::PathHome(p) => { /* home path like ~/foo */ }
|
||||
ast::Expr::PathSearch(p) => { /* search path like <nixpkgs> */ }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Using the `Path` enum
|
||||
|
||||
If you need to handle all path types uniformly, use the `ast::Path` enum:
|
||||
|
||||
```rust
|
||||
use rnix::ast::{AstNode, Path};
|
||||
|
||||
// Cast any path node to the Path enum
|
||||
if let Some(path) = Path::cast(node) {
|
||||
match path {
|
||||
Path::PathAbs(p) => { /* ... */ }
|
||||
Path::PathRel(p) => { /* ... */ }
|
||||
Path::PathHome(p) => { /* ... */ }
|
||||
Path::PathSearch(p) => { /* ... */ }
|
||||
}
|
||||
|
||||
// Or use helper methods
|
||||
if path.is_search() {
|
||||
// Search paths don't support interpolation
|
||||
}
|
||||
|
||||
// Get parts from any path type
|
||||
let parts = path.parts();
|
||||
}
|
||||
```
|
||||
|
||||
#### `Path::parts()` return type change
|
||||
|
||||
The `parts()` method now returns `Vec<InterpolPart<PathContent>>` instead of `impl Iterator<...>`:
|
||||
|
||||
```rust
|
||||
// Before:
|
||||
let mut parts = path.parts();
|
||||
let first = parts.next();
|
||||
|
||||
// After:
|
||||
let parts = path.parts();
|
||||
let first = parts.first();
|
||||
```
|
||||
|
||||
### Double slashes in paths are now syntax errors
|
||||
|
||||
Paths containing `//` (e.g., `foo//bar`) are now tokenized as `TOKEN_ERROR`. This matches Nix's behavior where such paths are invalid.
|
||||
88
third_party/crates/rnix-0.14.0/README.md
vendored
Normal file
88
third_party/crates/rnix-0.14.0/README.md
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# rnix-parser [](http://crates.io/crates/rnix) [](https://matrix.to/#/#rnix-lsp:matrix.org)
|
||||
|
||||
rnix is a parser for the [Nix language](https://nixos.org/nix/) written in Rust.
|
||||
|
||||
This can be used to manipulate the Nix AST and can for example be used for:
|
||||
|
||||
- Interactively render Nix on a GUI
|
||||
- Formatting Nix code
|
||||
- Rename identifiers
|
||||
|
||||
and a lot more!
|
||||
|
||||
rnix nowadays uses [@matklad](https://github.com/matklad)'s
|
||||
[rowan](https://crates.io/crates/rowan) crate to ensure:
|
||||
|
||||
- all span information is preserved, meaning you can use the AST to for
|
||||
example apply highlighting
|
||||
- printing out the AST prints out 100% the original code. This is not an
|
||||
over-exaggeration, even completely invalid nix code such as this README can
|
||||
be intact after a parsing session (though the AST will mark errnous nodes)
|
||||
- easy ways to walk the tree without resorting to recursion
|
||||
|
||||
## Demo
|
||||
|
||||
Examples can be found in the `examples/` directory.
|
||||
|
||||
You may also want to see
|
||||
[nix-explorer](https://gitlab.com/jD91mZM2/nix-explorer): An example
|
||||
that highlights AST nodes in Nix code. This demonstrates how
|
||||
whitespaces and commands are preserved.
|
||||
|
||||
## Hacking
|
||||
|
||||
Tests can be run with `cargo test`.
|
||||
|
||||
In order to update all `.expect`-files to the currently expected results,
|
||||
you may run `UPDATE_TESTS=1 cargo test`.
|
||||
|
||||
You can parse Nix expressions from standard input using the `from-stdin` example.
|
||||
To try that, run the following in your shell:
|
||||
|
||||
```sh
|
||||
echo "[hello nix]" | cargo run --quiet --example from-stdin
|
||||
```
|
||||
|
||||
## Release Checklist
|
||||
|
||||
* Ensure that all PRs that were scheduled for the release are merged (or optionally move
|
||||
them to another milestone).
|
||||
* Close the milestone for the release (if any).
|
||||
* Run `cargo test` on `master` (or the branch to release from) with all changes being pulled in.
|
||||
* Apply the following patch to [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt):
|
||||
```diff
|
||||
diff --git a/Cargo.toml b/Cargo.toml
|
||||
index 0891350..edad471 100644
|
||||
--- a/Cargo.toml
|
||||
+++ b/Cargo.toml
|
||||
@@ -13,6 +13,9 @@ repository = "https://github.com/nix-community/nixpkgs-fmt"
|
||||
[workspace]
|
||||
members = [ "./wasm" ]
|
||||
|
||||
+[patch.crates-io]
|
||||
+rnix = { path = "/home/ma27/Projects/rnix-parser" }
|
||||
+
|
||||
[dependencies]
|
||||
rnix = "0.9.0"
|
||||
smol_str = "0.1.17"
|
||||
```
|
||||
|
||||
and run `cargo test`.
|
||||
|
||||
While it's planned to add [fuzzing to `rnix-parser` as well](https://github.com/nix-community/rnix-parser/issues/32),
|
||||
`nixpkgs-fmt` has a decent test-suite that would've helped to catch regressions in the past.
|
||||
|
||||
__Note:__ API changes are OK (and fixes should be contributed to `nixpkgs-fmt`), behavioral changes
|
||||
are not unless explicitly discussed before.
|
||||
* Update the [CHANGELOG.md](https://github.com/nix-community/rnix-parser/blob/master/CHANGELOG.md).
|
||||
* Bump the version number in [Cargo.toml](https://github.com/nix-community/rnix-parser/blob/master/Cargo.toml) & re-run `cargo build` to refresh the lockfile.
|
||||
* Commit & run `nix build`.
|
||||
* Tag the release and push everything.
|
||||
* As soon as the CI has completed, run `cargo publish`.
|
||||
|
||||
# RIP jd91mzm2
|
||||
|
||||
Sadly, the original author of this project, [@jD91mZM2 has passed
|
||||
away](https://www.redox-os.org/news/open-source-mental-health/). His online
|
||||
presence was anonymous and what we have left is his code. This is but one of
|
||||
his many repos that he contributed to.
|
||||
24853
third_party/crates/rnix-0.14.0/benches/all-packages.nix
vendored
Normal file
24853
third_party/crates/rnix-0.14.0/benches/all-packages.nix
vendored
Normal file
File diff suppressed because it is too large
Load Diff
15
third_party/crates/rnix-0.14.0/benches/all-packages.rs
vendored
Normal file
15
third_party/crates/rnix-0.14.0/benches/all-packages.rs
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
|
||||
|
||||
fn all_packages(c: &mut Criterion) {
|
||||
let input = include_str!("all-packages.nix");
|
||||
let mut group = c.benchmark_group("all-packages");
|
||||
group.throughput(Throughput::Bytes(input.len() as u64));
|
||||
group.sample_size(30);
|
||||
group.bench_with_input("all-packages", input, move |b, input| {
|
||||
b.iter(|| rnix::Root::parse(input))
|
||||
});
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, all_packages);
|
||||
criterion_main!(benches);
|
||||
9
third_party/crates/rnix-0.14.0/default.nix
vendored
Normal file
9
third_party/crates/rnix-0.14.0/default.nix
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
let
|
||||
flake-compat = builtins.fetchTarball {
|
||||
url = "https://github.com/edolstra/flake-compat/archive/12c64ca55c1014cdc1b16ed5a804aa8576601ff2.tar.gz";
|
||||
sha256 = "0jm6nzb83wa6ai17ly9fzpqc40wg1viib8klq8lby54agpl213w5";
|
||||
};
|
||||
in
|
||||
(import flake-compat {
|
||||
src = ./.;
|
||||
}).defaultNix.default
|
||||
24
third_party/crates/rnix-0.14.0/examples/dump-ast.rs
vendored
Normal file
24
third_party/crates/rnix-0.14.0/examples/dump-ast.rs
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let mut iter = env::args().skip(1).peekable();
|
||||
if iter.peek().is_none() {
|
||||
eprintln!("Usage: dump-ast <file>");
|
||||
return;
|
||||
}
|
||||
for file in iter {
|
||||
let content = match fs::read_to_string(file) {
|
||||
Ok(content) => content,
|
||||
Err(err) => {
|
||||
eprintln!("error reading file: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let parse = rnix::Root::parse(&content);
|
||||
|
||||
for error in parse.errors() {
|
||||
println!("error: {}", error);
|
||||
}
|
||||
println!("{:#?}", parse.tree());
|
||||
}
|
||||
}
|
||||
67
third_party/crates/rnix-0.14.0/examples/error-report.rs
vendored
Normal file
67
third_party/crates/rnix-0.14.0/examples/error-report.rs
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
use rnix::ParseError;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let file = match env::args().nth(1) {
|
||||
Some(file) => file,
|
||||
None => {
|
||||
eprintln!("Usage: error-report <file>");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let content = match fs::read_to_string(&file) {
|
||||
Ok(content) => content,
|
||||
Err(err) => {
|
||||
eprintln!("error reading file: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let ast = rnix::Root::parse(&content);
|
||||
for error in ast.errors() {
|
||||
let range = match error {
|
||||
ParseError::Unexpected(range) => range,
|
||||
ParseError::UnexpectedExtra(range) => range,
|
||||
ParseError::UnexpectedWanted(_, range, _) => range,
|
||||
ParseError::UnexpectedDoubleBind(range) => range,
|
||||
ParseError::DuplicatedArgs(range, _) => range,
|
||||
err => {
|
||||
eprintln!("error: {}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
eprintln!("----- ERROR -----");
|
||||
eprintln!("{}", error);
|
||||
let start = usize::from(range.start());
|
||||
let start_row = content[..start].lines().count() - 1;
|
||||
let start_line = content[..start].rfind('\n').map(|i| i + 1).unwrap_or(0);
|
||||
let start_col = content[start_line..start].chars().count();
|
||||
let end = usize::from(range.end());
|
||||
let end_row = content[..end].lines().count() - 1;
|
||||
let end_line = content[..end].rfind('\n').map(|i| i + 1).unwrap_or(0);
|
||||
let end_col = content[end_line..end].chars().count();
|
||||
|
||||
let mut line_len = 1;
|
||||
let mut line = end_row;
|
||||
while line >= 10 {
|
||||
line /= 10;
|
||||
line_len += 1;
|
||||
}
|
||||
|
||||
let i = start_row.saturating_sub(1);
|
||||
for (i, line) in content.lines().enumerate().skip(i).take(end_row - i + 1) {
|
||||
println!("{:line_len$} {}", i + 1, line, line_len = line_len);
|
||||
if i >= start_row && i <= end_row {
|
||||
print!("{:line_len$} ", "", line_len = line_len);
|
||||
let mut end_col = if i == end_row { end_col } else { line.chars().count() };
|
||||
if i == start_row {
|
||||
print!("{:indent$}", "", indent = start_col);
|
||||
end_col -= start_col;
|
||||
}
|
||||
for _ in 0..end_col {
|
||||
print!("^");
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
third_party/crates/rnix-0.14.0/examples/from-stdin.rs
vendored
Normal file
13
third_party/crates/rnix-0.14.0/examples/from-stdin.rs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
use std::{io, io::Read};
|
||||
|
||||
fn main() {
|
||||
let mut content = String::new();
|
||||
io::stdin().read_to_string(&mut content).expect("could not read nix from stdin");
|
||||
let ast = rnix::Root::parse(&content);
|
||||
|
||||
for error in ast.errors() {
|
||||
println!("error: {}", error);
|
||||
}
|
||||
|
||||
println!("{:#?}", ast.tree());
|
||||
}
|
||||
95
third_party/crates/rnix-0.14.0/examples/list-fns.rs
vendored
Normal file
95
third_party/crates/rnix-0.14.0/examples/list-fns.rs
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
use std::{env, error::Error, fs};
|
||||
|
||||
use rnix::{
|
||||
ast::{self, AstToken, HasEntry},
|
||||
match_ast, NodeOrToken, SyntaxNode,
|
||||
};
|
||||
use rowan::ast::AstNode;
|
||||
|
||||
macro_rules! single_match {
|
||||
($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? => $captured:expr) => {
|
||||
match $expression {
|
||||
$( $pattern )|+ $( if $guard )? => Some($captured),
|
||||
_ => None
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let file = match env::args().nth(1) {
|
||||
Some(file) => file,
|
||||
None => {
|
||||
eprintln!("Usage: list-fns <file>");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let content = fs::read_to_string(&file)?;
|
||||
let ast = rnix::Root::parse(&content).ok()?;
|
||||
let expr = ast.expr().unwrap();
|
||||
let set = match expr {
|
||||
ast::Expr::AttrSet(set) => set,
|
||||
_ => return Err("root isn't a set".into()),
|
||||
};
|
||||
for entry in set.entries() {
|
||||
if let ast::Entry::AttrpathValue(attrpath_value) = entry {
|
||||
if let Some(ast::Expr::Lambda(lambda)) = attrpath_value.value() {
|
||||
let attrpath = attrpath_value.attrpath().unwrap();
|
||||
let ident = attrpath.attrs().last().and_then(|attr| match attr {
|
||||
ast::Attr::Ident(ident) => Some(ident),
|
||||
_ => None,
|
||||
});
|
||||
let s = ident.as_ref().map_or_else(
|
||||
|| "error".to_string(),
|
||||
|ident| ident.ident_token().unwrap().text().to_string(),
|
||||
);
|
||||
println!("Function name: {}", s);
|
||||
{
|
||||
let comments = comments_before(attrpath_value.syntax());
|
||||
if !comments.is_empty() {
|
||||
println!("--> Doc: {comments}");
|
||||
}
|
||||
}
|
||||
|
||||
let mut value = Some(lambda);
|
||||
while let Some(lambda) = value {
|
||||
let s = lambda
|
||||
.param()
|
||||
.as_ref()
|
||||
.map_or_else(|| "error".to_string(), |param| param.to_string());
|
||||
println!("-> Param: {}", s);
|
||||
{
|
||||
let comments = comments_before(lambda.syntax());
|
||||
if !comments.is_empty() {
|
||||
println!("--> Doc: {comments}");
|
||||
}
|
||||
}
|
||||
value =
|
||||
single_match!(lambda.body().unwrap(), ast::Expr::Lambda(lambda) => lambda);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn comments_before(node: &SyntaxNode) -> String {
|
||||
node.siblings_with_tokens(rowan::Direction::Prev)
|
||||
// rowan always returns the first node for some reason
|
||||
.skip(1)
|
||||
.map_while(|element| match element {
|
||||
NodeOrToken::Token(token) => match_ast! {
|
||||
match token {
|
||||
ast::Comment(it) => Some(Some(it)),
|
||||
ast::Whitespace(_) => Some(None),
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
.map(|s| s.text().trim().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n ")
|
||||
}
|
||||
19
third_party/crates/rnix-0.14.0/examples/preserve.rs
vendored
Normal file
19
third_party/crates/rnix-0.14.0/examples/preserve.rs
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let mut iter = env::args().skip(1).peekable();
|
||||
if iter.peek().is_none() {
|
||||
eprintln!("Usage: preserve <file>");
|
||||
return;
|
||||
}
|
||||
for file in iter {
|
||||
let content = match fs::read_to_string(file) {
|
||||
Ok(content) => content,
|
||||
Err(err) => {
|
||||
eprintln!("error reading file: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
print!("{}", rnix::Root::parse(&content).tree());
|
||||
}
|
||||
}
|
||||
48
third_party/crates/rnix-0.14.0/examples/test-nixpkgs.rs
vendored
Normal file
48
third_party/crates/rnix-0.14.0/examples/test-nixpkgs.rs
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
use std::{env, error::Error, fs, path::Path};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let path = env::var("NIX_PATH")?;
|
||||
let nixpkgs =
|
||||
path.split(':').find(|s| s.starts_with("nixpkgs=")).ok_or("no store path found")?;
|
||||
|
||||
println!("Nix store path: {}", nixpkgs);
|
||||
|
||||
recurse(Path::new(&nixpkgs["nixpkgs=".len()..]))
|
||||
}
|
||||
fn recurse(path: &Path) -> Result<(), Box<dyn Error>> {
|
||||
if path.metadata()?.is_file() {
|
||||
if path.extension().and_then(|s| s.to_str()) != Some("nix") {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("Checking {}", path.display());
|
||||
let original = fs::read_to_string(path)?;
|
||||
if original.trim().is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let parsed = rnix::Root::parse(&original).tree().to_string();
|
||||
if original != parsed {
|
||||
eprintln!("Original input does not match parsed output!");
|
||||
println!("Input:");
|
||||
println!("----------");
|
||||
println!("{}", original);
|
||||
println!("----------");
|
||||
println!("Output:");
|
||||
println!("----------");
|
||||
println!("{}", parsed);
|
||||
println!("----------");
|
||||
return Err("parsing error".into());
|
||||
}
|
||||
return Ok(());
|
||||
} else {
|
||||
for entry in path.read_dir()? {
|
||||
let entry = entry?;
|
||||
if entry.file_type()?.is_symlink() {
|
||||
continue;
|
||||
}
|
||||
recurse(&entry.path())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
116
third_party/crates/rnix-0.14.0/flake.lock
generated
vendored
Normal file
116
third_party/crates/rnix-0.14.0/flake.lock
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"nodes": {
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1769670296,
|
||||
"narHash": "sha256-0OzQzsufPwHUTJMAgVf+TXPFG+8x5xrYwz1/M/kI+7o=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "b00052920f71c43987b44c804196c083eb0fa1bf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"import-cargo": {
|
||||
"locked": {
|
||||
"lastModified": 1594305518,
|
||||
"narHash": "sha256-frtArgN42rSaEcEOYWg8sVPMUK+Zgch3c+wejcpX3DY=",
|
||||
"owner": "edolstra",
|
||||
"repo": "import-cargo",
|
||||
"rev": "25d40be4a73d40a2572e0cc233b83253554f06c5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "import-cargo",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1769461804,
|
||||
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"import-cargo": "import-cargo",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"utils": "utils"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1769526882,
|
||||
"narHash": "sha256-64CZX2vKsfSLKnTCZ0pbc1jPvixWWwuT382g3QHBz5c=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "40cda2f4bd585c1cb99ae4eb025968b8dc2eec42",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
85
third_party/crates/rnix-0.14.0/flake.nix
vendored
Normal file
85
third_party/crates/rnix-0.14.0/flake.nix
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
description = "Rust-based parser for nix files";
|
||||
|
||||
inputs = {
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
import-cargo.url = "github:edolstra/import-cargo";
|
||||
fenix = {
|
||||
url = "github:nix-community/fenix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, utils, import-cargo, fenix }:
|
||||
{
|
||||
overlay = final: prev: let
|
||||
target = final.stdenv.hostPlatform.rust.rustcTarget;
|
||||
flags = "--release --offline --target ${target}";
|
||||
inherit (import-cargo.builders) importCargo;
|
||||
in {
|
||||
rnix-parser = final.stdenv.mkDerivation {
|
||||
pname = "rnix-parser";
|
||||
version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version;
|
||||
src = final.lib.cleanSource ./.;
|
||||
nativeBuildInputs = with final; [
|
||||
rustc cargo
|
||||
(importCargo { lockFile = ./Cargo.lock; inherit (final) pkgs; }).cargoHome
|
||||
];
|
||||
|
||||
outputs = [ "out" "doc" ];
|
||||
doCheck = true;
|
||||
|
||||
buildPhase = ''
|
||||
cargo build ${flags}
|
||||
cargo doc ${flags}
|
||||
'';
|
||||
|
||||
checkPhase = ''
|
||||
cargo test ${flags}
|
||||
cargo bench
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/lib
|
||||
mkdir -p $doc/share/doc/rnix
|
||||
|
||||
cp -r ./target/${target}/doc $doc/share/doc/rnix
|
||||
cp ./target/${target}/release/librnix.rlib $out/lib/
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
// utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; overlays = [ self.overlay ]; };
|
||||
fenixPkgs = fenix.packages.${system};
|
||||
nightlyToolchain = fenixPkgs.combine [
|
||||
fenixPkgs.minimal.cargo
|
||||
fenixPkgs.minimal.rustc
|
||||
];
|
||||
in
|
||||
rec {
|
||||
# `nix develop`
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [ rustfmt rustc cargo clippy ];
|
||||
};
|
||||
|
||||
# `nix develop .#fuzz` - for running cargo-fuzz
|
||||
devShells.fuzz = pkgs.mkShell {
|
||||
buildInputs = [
|
||||
nightlyToolchain
|
||||
pkgs.cargo-fuzz
|
||||
];
|
||||
# libFuzzer needs libstdc++
|
||||
LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib";
|
||||
};
|
||||
|
||||
# Backwards compat
|
||||
devShell = devShells.default;
|
||||
|
||||
packages.rnix-parser = pkgs.rnix-parser;
|
||||
defaultPackage = packages.rnix-parser;
|
||||
}
|
||||
);
|
||||
}
|
||||
1
third_party/crates/rnix-0.14.0/rustfmt.toml
vendored
Normal file
1
third_party/crates/rnix-0.14.0/rustfmt.toml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
use_small_heuristics = "Max"
|
||||
9
third_party/crates/rnix-0.14.0/shell.nix
vendored
Normal file
9
third_party/crates/rnix-0.14.0/shell.nix
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
let
|
||||
flake-compat = builtins.fetchTarball {
|
||||
url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz";
|
||||
sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2";
|
||||
};
|
||||
in
|
||||
(import flake-compat {
|
||||
src = ./.;
|
||||
}).shellNix.default
|
||||
73
third_party/crates/rnix-0.14.0/src/ast.rs
vendored
Normal file
73
third_party/crates/rnix-0.14.0/src/ast.rs
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
//! Provides a type system for the AST, in some sense
|
||||
|
||||
mod expr_ext;
|
||||
mod interpol;
|
||||
mod nodes;
|
||||
mod operators;
|
||||
mod path_util;
|
||||
|
||||
pub use path_util::Path;
|
||||
mod str_util;
|
||||
mod tokens;
|
||||
|
||||
use crate::{NixLanguage, SyntaxKind, SyntaxToken};
|
||||
|
||||
pub use expr_ext::LiteralKind;
|
||||
pub use interpol::*;
|
||||
pub use nodes::*;
|
||||
pub use operators::{BinOpKind, UnaryOpKind};
|
||||
pub use tokens::*;
|
||||
|
||||
pub trait AstNode: rowan::ast::AstNode<Language = NixLanguage> {}
|
||||
|
||||
impl<T> AstNode for T where T: rowan::ast::AstNode<Language = NixLanguage> {}
|
||||
|
||||
pub trait AstToken {
|
||||
fn can_cast(from: SyntaxKind) -> bool
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Cast an untyped token into this strongly-typed token. This will return
|
||||
/// None if the type was not correct.
|
||||
fn cast(from: SyntaxToken) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn syntax(&self) -> &SyntaxToken;
|
||||
}
|
||||
|
||||
mod support {
|
||||
use rowan::ast::AstChildren;
|
||||
|
||||
use super::{AstNode, AstToken};
|
||||
use crate::{SyntaxElement, SyntaxKind, SyntaxToken};
|
||||
|
||||
pub(super) fn nth<N: AstNode, NN: AstNode>(parent: &N, n: usize) -> Option<NN> {
|
||||
parent.syntax().children().flat_map(NN::cast).nth(n)
|
||||
}
|
||||
|
||||
pub(super) fn children<N: AstNode, NN: AstNode>(parent: &N) -> AstChildren<NN> {
|
||||
rowan::ast::support::children(parent.syntax())
|
||||
}
|
||||
|
||||
pub(super) fn token<N: AstNode, T: AstToken>(parent: &N) -> Option<T> {
|
||||
children_tokens(parent).next()
|
||||
}
|
||||
|
||||
/// Token untyped
|
||||
pub(super) fn token_u<N: AstNode>(parent: &N, kind: SyntaxKind) -> Option<SyntaxToken> {
|
||||
children_tokens_u(parent).find(|it| it.kind() == kind)
|
||||
}
|
||||
|
||||
pub(super) fn children_tokens<N: AstNode, T: AstToken>(parent: &N) -> impl Iterator<Item = T> {
|
||||
parent
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(SyntaxElement::into_token)
|
||||
.filter_map(T::cast)
|
||||
}
|
||||
|
||||
pub(super) fn children_tokens_u<N: AstNode>(parent: &N) -> impl Iterator<Item = SyntaxToken> {
|
||||
parent.syntax().children_with_tokens().filter_map(SyntaxElement::into_token)
|
||||
}
|
||||
}
|
||||
29
third_party/crates/rnix-0.14.0/src/ast/expr_ext.rs
vendored
Normal file
29
third_party/crates/rnix-0.14.0/src/ast/expr_ext.rs
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
use crate::ast::{self, support::*};
|
||||
|
||||
// this is a separate type because it mixes tokens and nodes
|
||||
// for example, a Str is a node because it can contain nested subexpressions but an Integer is a token.
|
||||
// This means that we have to write it out manually instead of using the macro to create the type for us.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum LiteralKind {
|
||||
Float(ast::Float),
|
||||
Integer(ast::Integer),
|
||||
Uri(ast::Uri),
|
||||
}
|
||||
|
||||
impl ast::Literal {
|
||||
pub fn kind(&self) -> LiteralKind {
|
||||
if let Some(it) = token(self) {
|
||||
return LiteralKind::Float(it);
|
||||
}
|
||||
|
||||
if let Some(it) = token(self) {
|
||||
return LiteralKind::Integer(it);
|
||||
}
|
||||
|
||||
if let Some(it) = token(self) {
|
||||
return LiteralKind::Uri(it);
|
||||
}
|
||||
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
5
third_party/crates/rnix-0.14.0/src/ast/interpol.rs
vendored
Normal file
5
third_party/crates/rnix-0.14.0/src/ast/interpol.rs
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum InterpolPart<T> {
|
||||
Literal(T),
|
||||
Interpolation(super::Interpol),
|
||||
}
|
||||
464
third_party/crates/rnix-0.14.0/src/ast/nodes.rs
vendored
Normal file
464
third_party/crates/rnix-0.14.0/src/ast/nodes.rs
vendored
Normal file
@@ -0,0 +1,464 @@
|
||||
use crate::{NixLanguage, SyntaxKind, SyntaxKind::*, SyntaxNode, SyntaxToken};
|
||||
|
||||
use super::{operators::BinOpKind, support::*, AstNode, UnaryOpKind};
|
||||
use rowan::ast::{AstChildren, AstNode as OtherAstNode};
|
||||
|
||||
pub trait HasEntry: AstNode {
|
||||
fn entries(&self) -> AstChildren<Entry>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
children(self)
|
||||
}
|
||||
|
||||
fn attrpath_values(&self) -> AstChildren<AttrpathValue>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
children(self)
|
||||
}
|
||||
|
||||
fn inherits(&self) -> AstChildren<Inherit>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
children(self)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! node {
|
||||
(
|
||||
#[from($kind:ident)]
|
||||
$(#[$meta:meta])*
|
||||
struct $name:ident;
|
||||
) => {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
$(#[$meta])*
|
||||
pub struct $name(pub(super) SyntaxNode);
|
||||
|
||||
impl std::fmt::Display for $name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl rowan::ast::AstNode for $name {
|
||||
type Language = crate::NixLanguage;
|
||||
|
||||
fn can_cast(kind: crate::SyntaxKind) -> bool {
|
||||
kind == $kind
|
||||
}
|
||||
|
||||
fn cast(from: SyntaxNode) -> Option<Self> {
|
||||
if Self::can_cast(from.kind()) {
|
||||
Some(Self(from))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
pub const KIND: SyntaxKind = $kind;
|
||||
}
|
||||
};
|
||||
(
|
||||
#[from($($variant:ident),* $(,)?)]
|
||||
$(#[$meta:meta])*
|
||||
enum $name:ident;
|
||||
) => {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
$(#[$meta])*
|
||||
pub enum $name {
|
||||
$(
|
||||
$variant($variant),
|
||||
)*
|
||||
}
|
||||
|
||||
impl std::fmt::Display for $name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl rowan::ast::AstNode for $name {
|
||||
type Language = NixLanguage;
|
||||
|
||||
fn can_cast(kind: SyntaxKind) -> bool {
|
||||
matches!(kind, $($variant::KIND)|*)
|
||||
}
|
||||
|
||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||
let res = match syntax.kind() {
|
||||
$(
|
||||
$variant::KIND => $name::$variant($variant(syntax))
|
||||
),*,
|
||||
_ => return None,
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
fn syntax(&self) -> &SyntaxNode {
|
||||
match self {
|
||||
$(
|
||||
$name::$variant(it) => &it.0,
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
impl From<$variant> for $name {
|
||||
fn from(node: $variant) -> $name { $name::$variant(node) }
|
||||
}
|
||||
|
||||
impl TryFrom<$name> for $variant {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(node: $name) -> Result<$variant, ()> {
|
||||
match node {
|
||||
$name::$variant(it) => Ok(it),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! tg {
|
||||
(
|
||||
$(#[doc=$doc:tt])?
|
||||
$name:ident,
|
||||
$token:tt
|
||||
) => {
|
||||
$(#[doc=$doc])?
|
||||
pub fn $name(&self) -> Option<SyntaxToken> {
|
||||
token_u(self, T![$token])
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! ng {
|
||||
(
|
||||
$(#[$meta:meta])*
|
||||
$name:ident,
|
||||
$ty:ty,
|
||||
$i:expr
|
||||
) => {
|
||||
$(#[$meta])*
|
||||
pub fn $name(&self) -> Option<$ty> {
|
||||
nth(self, $i)
|
||||
}
|
||||
};
|
||||
(
|
||||
$(#[$meta:meta])*
|
||||
$name:ident,
|
||||
[$ty:ty]
|
||||
) => {
|
||||
$(#[$meta])*
|
||||
pub fn $name(&self) -> AstChildren<$ty> {
|
||||
children(self)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
node! { #[from(NODE_LITERAL)] struct Literal; }
|
||||
|
||||
node! {
|
||||
#[from(
|
||||
Apply,
|
||||
Assert,
|
||||
Error,
|
||||
IfElse,
|
||||
Select,
|
||||
Str,
|
||||
PathAbs,
|
||||
PathRel,
|
||||
PathHome,
|
||||
PathSearch,
|
||||
Literal,
|
||||
Lambda,
|
||||
LegacyLet,
|
||||
LetIn,
|
||||
List,
|
||||
BinOp,
|
||||
Paren,
|
||||
Root,
|
||||
AttrSet,
|
||||
UnaryOp,
|
||||
Ident,
|
||||
With,
|
||||
HasAttr,
|
||||
CurPos,
|
||||
)]
|
||||
/// An expression. The fundamental nix ast type.
|
||||
enum Expr;
|
||||
}
|
||||
|
||||
node! {
|
||||
#[from(
|
||||
Ident,
|
||||
Dynamic,
|
||||
Str,
|
||||
)]
|
||||
enum Attr;
|
||||
}
|
||||
|
||||
node! { #[from(NODE_IDENT)] struct Ident; }
|
||||
|
||||
impl Ident {
|
||||
// A NODE_IDENT may either have a nested TOKEN_OR if the identifier was "or" or TOKEN_IDENT for everything else
|
||||
tg! { ident_token, TOKEN_IDENT }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_APPLY)] struct Apply; }
|
||||
|
||||
impl Apply {
|
||||
ng! { lambda, Expr, 0 }
|
||||
ng! { argument, Expr, 1 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_ASSERT)] struct Assert; }
|
||||
|
||||
impl Assert {
|
||||
tg! { assert_token, assert }
|
||||
ng! { condition, Expr, 0 }
|
||||
ng! { body, Expr, 1 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_ATTRPATH)] struct Attrpath; }
|
||||
|
||||
impl Attrpath {
|
||||
ng! { attrs, [Attr] }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_DYNAMIC)] struct Dynamic; }
|
||||
|
||||
impl Dynamic {
|
||||
tg! { interpol_start_token, TOKEN_INTERPOL_START }
|
||||
ng! { expr, Expr, 0 }
|
||||
tg! { interpol_end_token, TOKEN_INTERPOL_END }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_ERROR)] struct Error; }
|
||||
|
||||
node! { #[from(NODE_IF_ELSE)] struct IfElse; }
|
||||
|
||||
impl IfElse {
|
||||
tg! { if_token, if }
|
||||
ng! { condition, Expr, 0 }
|
||||
tg! { then_token, then }
|
||||
ng! { body, Expr, 1 }
|
||||
tg! { else_token, else }
|
||||
ng! { else_body, Expr, 2 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_SELECT)] struct Select; }
|
||||
|
||||
impl Select {
|
||||
ng! { expr, Expr, 0 }
|
||||
tg! { dot_token, . }
|
||||
ng! { attrpath, Attrpath, 0 }
|
||||
tg! { or_token, or }
|
||||
ng! { default_expr, Expr, 1 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_INHERIT)] struct Inherit; }
|
||||
|
||||
impl Inherit {
|
||||
tg! { inherit_token, inherit }
|
||||
ng! { from, InheritFrom, 0 }
|
||||
ng! { attrs, [Attr] }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_INHERIT_FROM)] struct InheritFrom; }
|
||||
|
||||
impl InheritFrom {
|
||||
tg! { l_paren_token, '(' }
|
||||
ng! { expr, Expr, 0 }
|
||||
tg! { r_paren_token, ')' }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_PATH_ABS)] struct PathAbs; }
|
||||
node! { #[from(NODE_PATH_REL)] struct PathRel; }
|
||||
node! { #[from(NODE_PATH_HOME)] struct PathHome; }
|
||||
node! { #[from(NODE_PATH_SEARCH)] struct PathSearch; }
|
||||
|
||||
node! {
|
||||
#[from(
|
||||
PathAbs,
|
||||
PathRel,
|
||||
PathHome,
|
||||
PathSearch,
|
||||
)]
|
||||
enum Path;
|
||||
}
|
||||
|
||||
node! { #[from(NODE_STRING)] struct Str; }
|
||||
|
||||
node! { #[from(NODE_INTERPOL)] struct Interpol; }
|
||||
|
||||
impl Interpol {
|
||||
ng! { expr, Expr, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_LAMBDA)] struct Lambda; }
|
||||
|
||||
impl Lambda {
|
||||
ng! { param, Param, 0 }
|
||||
tg! { token_colon, : }
|
||||
ng! { body, Expr, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_LEGACY_LET)] struct LegacyLet; }
|
||||
|
||||
impl HasEntry for LegacyLet {}
|
||||
|
||||
impl LegacyLet {
|
||||
tg! { let_token, let }
|
||||
tg! { curly_open_token, '{' }
|
||||
tg! { curly_close_token, '}' }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_LET_IN)] struct LetIn; }
|
||||
|
||||
impl HasEntry for LetIn {}
|
||||
|
||||
impl LetIn {
|
||||
tg! { let_token, let }
|
||||
tg! { in_token, in }
|
||||
ng! { body, Expr, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_LIST)] struct List; }
|
||||
|
||||
impl List {
|
||||
tg! { l_brack_token, '[' }
|
||||
ng! { items, [Expr] }
|
||||
tg! { r_brack_token, ']' }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_BIN_OP)] struct BinOp; }
|
||||
|
||||
impl BinOp {
|
||||
ng! { lhs, Expr, 0 }
|
||||
|
||||
pub fn operator(&self) -> Option<BinOpKind> {
|
||||
children_tokens_u(self).find_map(|t| BinOpKind::from_kind(t.kind()))
|
||||
}
|
||||
|
||||
ng! { rhs, Expr, 1 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_PAREN)] struct Paren; }
|
||||
|
||||
impl Paren {
|
||||
tg! { l_paren_token, '(' }
|
||||
ng! { expr, Expr, 0 }
|
||||
tg! { r_paren_token, ')' }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_PAT_BIND)] struct PatBind; }
|
||||
|
||||
impl PatBind {
|
||||
ng! { ident, Ident, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_PAT_ENTRY)] struct PatEntry; }
|
||||
|
||||
impl PatEntry {
|
||||
ng! { ident, Ident, 0 }
|
||||
tg! { question_token, ? }
|
||||
ng! { default, Expr, 1 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_IDENT_PARAM)] struct IdentParam; }
|
||||
|
||||
impl IdentParam {
|
||||
ng! { ident, Ident, 0 }
|
||||
}
|
||||
|
||||
node! {
|
||||
#[from(
|
||||
Pattern,
|
||||
IdentParam,
|
||||
)]
|
||||
enum Param;
|
||||
}
|
||||
|
||||
node! { #[from(NODE_PATTERN)] struct Pattern; }
|
||||
|
||||
impl Pattern {
|
||||
tg! { at_token, @ }
|
||||
ng! { pat_entries, [PatEntry] }
|
||||
tg! { ellipsis_token, ... }
|
||||
ng! { pat_bind, PatBind, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_ROOT)] struct Root; }
|
||||
|
||||
impl Root {
|
||||
ng! { expr, Expr, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_ATTR_SET)] struct AttrSet; }
|
||||
|
||||
impl HasEntry for AttrSet {}
|
||||
|
||||
impl AttrSet {
|
||||
tg! { rec_token, rec }
|
||||
tg! { l_curly_token, '{' }
|
||||
tg! { r_curly_token, '}' }
|
||||
}
|
||||
|
||||
node! {
|
||||
#[from(
|
||||
Inherit,
|
||||
AttrpathValue,
|
||||
)]
|
||||
enum Entry;
|
||||
}
|
||||
|
||||
node! { #[from(NODE_ATTRPATH_VALUE)] struct AttrpathValue; }
|
||||
|
||||
impl AttrpathValue {
|
||||
ng! { attrpath, Attrpath, 0 }
|
||||
tg! { assign_token, = }
|
||||
ng! { value, Expr, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_UNARY_OP)] struct UnaryOp; }
|
||||
|
||||
impl UnaryOp {
|
||||
pub fn operator(&self) -> Option<UnaryOpKind> {
|
||||
children_tokens_u(self).find_map(|t| UnaryOpKind::from_kind(t.kind()))
|
||||
}
|
||||
ng! { expr, Expr, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_WITH)] struct With; }
|
||||
|
||||
impl With {
|
||||
tg! { with_token, with }
|
||||
ng! { namespace, Expr, 0 }
|
||||
tg! { semicolon_token, ; }
|
||||
ng! { body, Expr, 1 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_HAS_ATTR)] struct HasAttr; }
|
||||
|
||||
impl HasAttr {
|
||||
ng! { expr, Expr, 0 }
|
||||
tg! { question_token, ? }
|
||||
ng! { attrpath, Attrpath, 0 }
|
||||
}
|
||||
|
||||
node! { #[from(NODE_CUR_POS)] struct CurPos; }
|
||||
|
||||
impl CurPos {
|
||||
tg! { cur_pos_token, __curPos }
|
||||
}
|
||||
71
third_party/crates/rnix-0.14.0/src/ast/operators.rs
vendored
Normal file
71
third_party/crates/rnix-0.14.0/src/ast/operators.rs
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
use crate::SyntaxKind::{self, *};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum BinOpKind {
|
||||
Concat,
|
||||
Update,
|
||||
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
|
||||
And,
|
||||
Equal,
|
||||
Implication,
|
||||
Less,
|
||||
LessOrEq,
|
||||
More,
|
||||
MoreOrEq,
|
||||
NotEqual,
|
||||
Or,
|
||||
PipeRight,
|
||||
PipeLeft,
|
||||
}
|
||||
|
||||
impl BinOpKind {
|
||||
/// Get the operation kind from a SyntaxKind in the AST
|
||||
pub fn from_kind(token: SyntaxKind) -> Option<Self> {
|
||||
match token {
|
||||
TOKEN_CONCAT => Some(BinOpKind::Concat),
|
||||
TOKEN_UPDATE => Some(BinOpKind::Update),
|
||||
|
||||
TOKEN_ADD => Some(BinOpKind::Add),
|
||||
TOKEN_SUB => Some(BinOpKind::Sub),
|
||||
TOKEN_MUL => Some(BinOpKind::Mul),
|
||||
TOKEN_DIV => Some(BinOpKind::Div),
|
||||
|
||||
TOKEN_AND_AND => Some(BinOpKind::And),
|
||||
TOKEN_EQUAL => Some(BinOpKind::Equal),
|
||||
TOKEN_IMPLICATION => Some(BinOpKind::Implication),
|
||||
TOKEN_LESS => Some(BinOpKind::Less),
|
||||
TOKEN_LESS_OR_EQ => Some(BinOpKind::LessOrEq),
|
||||
TOKEN_MORE => Some(BinOpKind::More),
|
||||
TOKEN_MORE_OR_EQ => Some(BinOpKind::MoreOrEq),
|
||||
TOKEN_NOT_EQUAL => Some(BinOpKind::NotEqual),
|
||||
TOKEN_OR_OR => Some(BinOpKind::Or),
|
||||
|
||||
TOKEN_PIPE_RIGHT => Some(BinOpKind::PipeRight),
|
||||
TOKEN_PIPE_LEFT => Some(BinOpKind::PipeLeft),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum UnaryOpKind {
|
||||
Invert,
|
||||
Negate,
|
||||
}
|
||||
|
||||
impl UnaryOpKind {
|
||||
/// Get the operation kind from a token in the AST
|
||||
pub fn from_kind(kind: SyntaxKind) -> Option<Self> {
|
||||
match kind {
|
||||
TOKEN_INVERT => Some(UnaryOpKind::Invert),
|
||||
TOKEN_SUB => Some(UnaryOpKind::Negate),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
204
third_party/crates/rnix-0.14.0/src/ast/path_util.rs
vendored
Normal file
204
third_party/crates/rnix-0.14.0/src/ast/path_util.rs
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
use crate::kinds::SyntaxKind::{TOKEN_PATH_ABS, TOKEN_PATH_HOME, TOKEN_PATH_REL};
|
||||
|
||||
use rowan::{ast::AstNode as OtherAstNode, NodeOrToken};
|
||||
|
||||
pub use super::nodes::Path;
|
||||
use super::{
|
||||
nodes::{PathAbs, PathHome, PathRel, PathSearch},
|
||||
AstToken, InterpolPart, PathContent,
|
||||
};
|
||||
use crate::ast;
|
||||
|
||||
fn extract_path_parts<T: ast::AstNode>(node: &T) -> Vec<InterpolPart<PathContent>> {
|
||||
node.syntax()
|
||||
.children_with_tokens()
|
||||
.map(|child| match child {
|
||||
NodeOrToken::Token(token) => {
|
||||
debug_assert!(matches!(
|
||||
token.kind(),
|
||||
TOKEN_PATH_ABS | TOKEN_PATH_REL | TOKEN_PATH_HOME
|
||||
));
|
||||
InterpolPart::Literal(PathContent::cast(token).unwrap())
|
||||
}
|
||||
NodeOrToken::Node(node) => {
|
||||
InterpolPart::Interpolation(ast::Interpol::cast(node).unwrap())
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Direct methods for interpolatable path types
|
||||
impl PathAbs {
|
||||
pub fn parts(&self) -> Vec<InterpolPart<PathContent>> {
|
||||
extract_path_parts(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PathRel {
|
||||
pub fn parts(&self) -> Vec<InterpolPart<PathContent>> {
|
||||
extract_path_parts(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PathHome {
|
||||
pub fn parts(&self) -> Vec<InterpolPart<PathContent>> {
|
||||
extract_path_parts(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Direct methods for search path
|
||||
impl PathSearch {
|
||||
/// Get the content of a search path
|
||||
pub fn content(&self) -> Option<PathContent> {
|
||||
self.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|child| child.into_token().and_then(PathContent::cast))
|
||||
.next()
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension methods for the Path enum
|
||||
impl Path {
|
||||
/// Get parts from any path type in a unified way
|
||||
pub fn parts(&self) -> Vec<InterpolPart<PathContent>> {
|
||||
match self {
|
||||
// For interpolatable paths, get their parts
|
||||
Path::PathAbs(p) => p.parts(),
|
||||
Path::PathRel(p) => p.parts(),
|
||||
Path::PathHome(p) => p.parts(),
|
||||
// For search paths, return a single literal component if content exists
|
||||
Path::PathSearch(p) => {
|
||||
if let Some(content) = p.content() {
|
||||
vec![InterpolPart::Literal(content)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_search(&self) -> bool {
|
||||
matches!(self, Path::PathSearch(_))
|
||||
}
|
||||
|
||||
pub fn is_interpolatable(&self) -> bool {
|
||||
!self.is_search()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rowan::ast::AstNode;
|
||||
|
||||
use super::InterpolPart;
|
||||
use crate::{
|
||||
ast::{self, Path},
|
||||
Root,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_path_types() {
|
||||
// Absolute path
|
||||
let inp = "/foo/bar";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
if let ast::Expr::PathAbs(p) = expr {
|
||||
let path = Path::cast(p.syntax().clone()).unwrap();
|
||||
assert!(path.is_interpolatable());
|
||||
assert!(!path.is_search());
|
||||
}
|
||||
|
||||
// Search path
|
||||
let inp = "<nixpkgs>";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
if let ast::Expr::PathSearch(p) = expr {
|
||||
let path = Path::cast(p.syntax().clone()).unwrap();
|
||||
assert!(!path.is_interpolatable());
|
||||
assert!(path.is_search());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parts() {
|
||||
// Test parts with absolute path
|
||||
let inp = "/foo/bar";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
if let ast::Expr::PathAbs(p) = expr {
|
||||
let path = Path::cast(p.syntax().clone()).unwrap();
|
||||
|
||||
let parts = path.parts();
|
||||
assert_eq!(parts.len(), 1);
|
||||
|
||||
match &parts[0] {
|
||||
InterpolPart::Literal(content) => {
|
||||
assert_eq!(content.text(), "/foo/bar");
|
||||
}
|
||||
_ => panic!("Expected literal part"),
|
||||
}
|
||||
}
|
||||
|
||||
// Test parts with interpolated path
|
||||
let inp = r#"./a/${"hello"}"#;
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
if let ast::Expr::PathRel(p) = expr {
|
||||
let path = Path::cast(p.syntax().clone()).unwrap();
|
||||
|
||||
let parts = path.parts();
|
||||
assert_eq!(parts.len(), 2);
|
||||
|
||||
match &parts[0] {
|
||||
InterpolPart::Literal(content) => {
|
||||
assert_eq!(content.text(), "./a/");
|
||||
}
|
||||
_ => panic!("Expected literal part"),
|
||||
}
|
||||
|
||||
match &parts[1] {
|
||||
InterpolPart::Interpolation(_) => {} // Success
|
||||
_ => panic!("Expected interpolation part"),
|
||||
}
|
||||
}
|
||||
|
||||
// Test parts with search path
|
||||
let inp = "<nixpkgs>";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
if let ast::Expr::PathSearch(p) = expr {
|
||||
let path = Path::cast(p.syntax().clone()).unwrap();
|
||||
|
||||
let parts = path.parts();
|
||||
assert_eq!(parts.len(), 1);
|
||||
|
||||
match &parts[0] {
|
||||
InterpolPart::Literal(content) => {
|
||||
assert_eq!(content.text(), "<nixpkgs>");
|
||||
}
|
||||
_ => panic!("Expected literal part"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_method_usage() {
|
||||
// Test direct parts() method on PathAbs
|
||||
let inp = "/foo/bar";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
if let ast::Expr::PathAbs(p) = expr {
|
||||
let parts = p.parts();
|
||||
assert_eq!(parts.len(), 1);
|
||||
|
||||
match &parts[0] {
|
||||
InterpolPart::Literal(content) => {
|
||||
assert_eq!(content.text(), "/foo/bar");
|
||||
}
|
||||
_ => panic!("Expected literal part"),
|
||||
}
|
||||
}
|
||||
|
||||
// Test direct content() method on PathSearch
|
||||
let inp = "<nixpkgs>";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
if let ast::Expr::PathSearch(p) = expr {
|
||||
let content = p.content().expect("Expected content");
|
||||
assert_eq!(content.text(), "<nixpkgs>");
|
||||
}
|
||||
}
|
||||
}
|
||||
363
third_party/crates/rnix-0.14.0/src/ast/str_util.rs
vendored
Normal file
363
third_party/crates/rnix-0.14.0/src/ast/str_util.rs
vendored
Normal file
@@ -0,0 +1,363 @@
|
||||
use crate::kinds::SyntaxKind::*;
|
||||
use rowan::{ast::AstNode as OtherAstNode, NodeOrToken};
|
||||
|
||||
use crate::ast;
|
||||
|
||||
use super::{support::children_tokens_u, AstToken, InterpolPart, StrContent};
|
||||
|
||||
impl ast::Str {
|
||||
pub fn parts(&self) -> impl Iterator<Item = InterpolPart<StrContent>> {
|
||||
self.syntax().children_with_tokens().filter_map(|child| match child {
|
||||
NodeOrToken::Token(token) if token.kind() == TOKEN_STRING_CONTENT => {
|
||||
Some(InterpolPart::Literal(StrContent::cast(token).unwrap()))
|
||||
}
|
||||
NodeOrToken::Token(token) => {
|
||||
assert!(token.kind() == TOKEN_STRING_START || token.kind() == TOKEN_STRING_END);
|
||||
None
|
||||
}
|
||||
NodeOrToken::Node(node) => {
|
||||
assert_eq!(node.kind(), NODE_INTERPOL);
|
||||
Some(InterpolPart::Interpolation(ast::Interpol::cast(node).unwrap()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn normalized_parts(&self) -> Vec<InterpolPart<String>> {
|
||||
let multiline = children_tokens_u(self).next().is_some_and(|t| t.text() == "''");
|
||||
let mut is_first_literal = true;
|
||||
let mut at_start_of_line = true;
|
||||
let mut min_indent = 1000000;
|
||||
let mut cur_indent = 0;
|
||||
let mut n = 0;
|
||||
let mut first_is_literal = false;
|
||||
|
||||
let parts: Vec<InterpolPart<StrContent>> = self.parts().collect();
|
||||
|
||||
if multiline {
|
||||
for part in &parts {
|
||||
match part {
|
||||
InterpolPart::Interpolation(_) => {
|
||||
if at_start_of_line {
|
||||
at_start_of_line = false;
|
||||
min_indent = min_indent.min(cur_indent);
|
||||
}
|
||||
n += 1;
|
||||
}
|
||||
InterpolPart::Literal(literal) => {
|
||||
let mut token_text = literal.syntax().text();
|
||||
|
||||
if n == 0 {
|
||||
first_is_literal = true;
|
||||
}
|
||||
|
||||
if is_first_literal && first_is_literal {
|
||||
is_first_literal = false;
|
||||
if let Some(p) = token_text.find('\n') {
|
||||
if token_text[0..p].chars().all(|c| c == ' ') {
|
||||
token_text = &token_text[p + 1..]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for c in token_text.chars() {
|
||||
if at_start_of_line {
|
||||
if c == ' ' {
|
||||
cur_indent += 1;
|
||||
} else if c == '\n' {
|
||||
cur_indent = 0;
|
||||
} else {
|
||||
at_start_of_line = false;
|
||||
min_indent = min_indent.min(cur_indent);
|
||||
}
|
||||
} else if c == '\n' {
|
||||
at_start_of_line = true;
|
||||
cur_indent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut normalized_parts = Vec::new();
|
||||
let mut cur_dropped = 0;
|
||||
let mut i = 0;
|
||||
is_first_literal = true;
|
||||
at_start_of_line = true;
|
||||
|
||||
for part in parts {
|
||||
match part {
|
||||
InterpolPart::Interpolation(interpol) => {
|
||||
at_start_of_line = false;
|
||||
cur_dropped = 0;
|
||||
normalized_parts.push(InterpolPart::Interpolation(interpol));
|
||||
i += 1;
|
||||
}
|
||||
InterpolPart::Literal(literal) => {
|
||||
let mut token_text = literal.syntax().text();
|
||||
|
||||
if multiline {
|
||||
if is_first_literal && first_is_literal {
|
||||
is_first_literal = false;
|
||||
if let Some(p) = token_text.find('\n') {
|
||||
if token_text[0..p].chars().all(|c| c == ' ') {
|
||||
token_text = &token_text[p + 1..];
|
||||
if token_text.is_empty() {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut str = String::new();
|
||||
for c in token_text.chars() {
|
||||
if at_start_of_line {
|
||||
if c == ' ' {
|
||||
if cur_dropped >= min_indent {
|
||||
str.push(c);
|
||||
}
|
||||
cur_dropped += 1;
|
||||
} else if c == '\n' {
|
||||
cur_dropped = 0;
|
||||
str.push(c);
|
||||
} else {
|
||||
at_start_of_line = false;
|
||||
cur_dropped = 0;
|
||||
str.push(c);
|
||||
}
|
||||
} else {
|
||||
str.push(c);
|
||||
if c == '\n' {
|
||||
at_start_of_line = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if i == n - 1 {
|
||||
if let Some(p) = str.rfind('\n') {
|
||||
if str[p + 1..].chars().all(|c| c == ' ') {
|
||||
str.truncate(p + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
normalized_parts.push(InterpolPart::Literal(unescape(&str, multiline)));
|
||||
i += 1;
|
||||
} else {
|
||||
normalized_parts
|
||||
.push(InterpolPart::Literal(unescape(token_text, multiline)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
normalized_parts
|
||||
}
|
||||
}
|
||||
|
||||
/// Interpret escape sequences in the nix string and return the converted value
|
||||
pub fn unescape(input: &str, multiline: bool) -> String {
|
||||
let mut output = String::new();
|
||||
let mut input = input.chars().peekable();
|
||||
loop {
|
||||
match input.next() {
|
||||
None => break,
|
||||
Some('"') if !multiline => break,
|
||||
Some('\\') if !multiline => match input.next() {
|
||||
None => break,
|
||||
Some('n') => output.push('\n'),
|
||||
Some('r') => output.push('\r'),
|
||||
Some('t') => output.push('\t'),
|
||||
Some(c) => output.push(c),
|
||||
},
|
||||
Some('\'') if multiline => match input.next() {
|
||||
None => {
|
||||
output.push('\'');
|
||||
}
|
||||
Some('\'') => match input.peek() {
|
||||
Some('\'') => {
|
||||
input.next().unwrap();
|
||||
output.push_str("''");
|
||||
}
|
||||
Some('$') => {
|
||||
input.next().unwrap();
|
||||
output.push('$');
|
||||
}
|
||||
Some('\\') => {
|
||||
input.next().unwrap();
|
||||
match input.next() {
|
||||
None => break,
|
||||
Some('n') => output.push('\n'),
|
||||
Some('r') => output.push('\r'),
|
||||
Some('t') => output.push('\t'),
|
||||
Some(c) => output.push(c),
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
},
|
||||
Some(c) => {
|
||||
output.push('\'');
|
||||
output.push(c);
|
||||
}
|
||||
},
|
||||
Some(c) => output.push(c),
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Root;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn string_unescapes() {
|
||||
assert_eq!(unescape(r#"Hello\n\"World\" :D"#, false), "Hello\n\"World\" :D");
|
||||
assert_eq!(unescape(r#"\"Hello\""#, false), "\"Hello\"");
|
||||
|
||||
assert_eq!(unescape(r#"Hello''\n'''World''' :D"#, true), "Hello\n''World'' :D");
|
||||
assert_eq!(unescape(r#""Hello""#, true), "\"Hello\"");
|
||||
}
|
||||
#[test]
|
||||
fn parts_leading_ws() {
|
||||
let inp = "''\n hello\n world''";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
match expr {
|
||||
ast::Expr::Str(str) => {
|
||||
assert_eq!(
|
||||
str.normalized_parts(),
|
||||
vec![InterpolPart::Literal("hello\nworld".to_string())]
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn parts_trailing_ws_single_line() {
|
||||
let inp = "''hello ''";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
match expr {
|
||||
ast::Expr::Str(str) => {
|
||||
assert_eq!(
|
||||
str.normalized_parts(),
|
||||
vec![InterpolPart::Literal("hello ".to_string())]
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn parts_trailing_ws_multiline() {
|
||||
let inp = "''hello\n ''";
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
match expr {
|
||||
ast::Expr::Str(str) => {
|
||||
assert_eq!(
|
||||
str.normalized_parts(),
|
||||
vec![InterpolPart::Literal("hello\n".to_string())]
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn parts() {
|
||||
use crate::{NixLanguage, SyntaxNode};
|
||||
use rowan::{GreenNodeBuilder, Language};
|
||||
|
||||
fn string_node(content: &str) -> ast::Str {
|
||||
let mut builder = GreenNodeBuilder::new();
|
||||
builder.start_node(NixLanguage::kind_to_raw(NODE_STRING));
|
||||
builder.token(NixLanguage::kind_to_raw(TOKEN_STRING_START), "''");
|
||||
builder.token(NixLanguage::kind_to_raw(TOKEN_STRING_CONTENT), content);
|
||||
builder.token(NixLanguage::kind_to_raw(TOKEN_STRING_END), "''");
|
||||
builder.finish_node();
|
||||
|
||||
ast::Str::cast(SyntaxNode::new_root(builder.finish())).unwrap()
|
||||
}
|
||||
|
||||
let txtin = r#"
|
||||
|trailing-whitespace
|
||||
|trailing-whitespace
|
||||
This is a multiline string :D
|
||||
indented by two
|
||||
\'\'\'\'\
|
||||
''${ interpolation was escaped }
|
||||
two single quotes: '''
|
||||
three single quotes: ''''
|
||||
"#
|
||||
.replace("|trailing-whitespace", "");
|
||||
|
||||
if let [InterpolPart::Literal(lit)] =
|
||||
&ast::Str::normalized_parts(&string_node(txtin.as_str()))[..]
|
||||
{
|
||||
assert_eq!(lit,
|
||||
// Get the below with nix repl
|
||||
" \n \nThis is a multiline string :D\n indented by two\n\\'\\'\\'\\'\\\n${ interpolation was escaped }\ntwo single quotes: ''\nthree single quotes: '''\n"
|
||||
);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parts_ast() {
|
||||
fn assert_eq_ast_ctn(it: &mut dyn Iterator<Item = InterpolPart<String>>, x: &str) {
|
||||
let tmp = it.next().expect("unexpected EOF");
|
||||
if let InterpolPart::Interpolation(astn) = tmp {
|
||||
assert_eq!(astn.expr().unwrap().syntax().to_string(), x);
|
||||
} else {
|
||||
unreachable!("unexpected literal {:?}", tmp);
|
||||
}
|
||||
}
|
||||
|
||||
let inp = r#"''
|
||||
|
||||
This version of Nixpkgs requires Nix >= ${requiredVersion}, please upgrade:
|
||||
|
||||
- If you are running NixOS, `nixos-rebuild' can be used to upgrade your system.
|
||||
|
||||
- Alternatively, with Nix > 2.0 `nix upgrade-nix' can be used to imperatively
|
||||
upgrade Nix. You may use `nix-env --version' to check which version you have.
|
||||
|
||||
- If you installed Nix using the install script (https://nixos.org/nix/install),
|
||||
it is safe to upgrade by running it again:
|
||||
|
||||
curl -L https://nixos.org/nix/install | sh
|
||||
|
||||
For more information, please see the NixOS release notes at
|
||||
https://nixos.org/nixos/manual or locally at
|
||||
${toString ./nixos/doc/manual/release-notes}.
|
||||
|
||||
If you need further help, see https://nixos.org/nixos/support.html
|
||||
''"#;
|
||||
let expr = Root::parse(inp).ok().unwrap().expr().unwrap();
|
||||
match expr {
|
||||
ast::Expr::Str(s) => {
|
||||
let mut it = s.normalized_parts().into_iter();
|
||||
assert_eq!(
|
||||
it.next().unwrap(),
|
||||
InterpolPart::Literal("\nThis version of Nixpkgs requires Nix >= ".to_string())
|
||||
);
|
||||
assert_eq_ast_ctn(&mut it, "requiredVersion");
|
||||
assert_eq!(it.next().unwrap(), InterpolPart::Literal(
|
||||
", please upgrade:\n\n- If you are running NixOS, `nixos-rebuild' can be used to upgrade your system.\n\n- Alternatively, with Nix > 2.0 `nix upgrade-nix' can be used to imperatively\n upgrade Nix. You may use `nix-env --version' to check which version you have.\n\n- If you installed Nix using the install script (https://nixos.org/nix/install),\n it is safe to upgrade by running it again:\n\n curl -L https://nixos.org/nix/install | sh\n\nFor more information, please see the NixOS release notes at\nhttps://nixos.org/nixos/manual or locally at\n".to_string()
|
||||
));
|
||||
assert_eq_ast_ctn(&mut it, "toString ./nixos/doc/manual/release-notes");
|
||||
assert_eq!(
|
||||
it.next().unwrap(),
|
||||
InterpolPart::Literal(
|
||||
".\n\nIf you need further help, see https://nixos.org/nixos/support.html\n"
|
||||
.to_string()
|
||||
)
|
||||
);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
174
third_party/crates/rnix-0.14.0/src/ast/tokens.rs
vendored
Normal file
174
third_party/crates/rnix-0.14.0/src/ast/tokens.rs
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
use core::num;
|
||||
|
||||
use crate::{
|
||||
ast::AstToken,
|
||||
SyntaxKind::{self, *},
|
||||
SyntaxToken,
|
||||
};
|
||||
|
||||
macro_rules! token {
|
||||
(
|
||||
#[from($kind:ident)]
|
||||
$(#[$meta:meta])*
|
||||
struct $name:ident;
|
||||
) => {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
$(#[$meta])*
|
||||
pub struct $name(pub(super) SyntaxToken);
|
||||
|
||||
impl std::fmt::Display for $name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.syntax(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl AstToken for $name {
|
||||
fn can_cast(kind: SyntaxKind) -> bool {
|
||||
$kind == kind
|
||||
}
|
||||
|
||||
fn cast(from: SyntaxToken) -> Option<Self> {
|
||||
if from.kind() == $kind {
|
||||
Some(Self(from))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn syntax(&self) -> &SyntaxToken {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
token! { #[from(TOKEN_WHITESPACE)] struct Whitespace; }
|
||||
|
||||
token! { #[from(TOKEN_COMMENT)] struct Comment; }
|
||||
|
||||
impl Comment {
|
||||
pub fn text(&self) -> &str {
|
||||
let text = self.syntax().text();
|
||||
// Handle both "#..." and "/*...*/" comments.
|
||||
match text.strip_prefix('#') {
|
||||
Some(s) => s,
|
||||
None => text.strip_prefix(r#"/*"#).unwrap().strip_suffix(r#"*/"#).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::ast;
|
||||
use crate::match_ast;
|
||||
use crate::Root;
|
||||
|
||||
use super::*;
|
||||
use rowan::ast::AstNode;
|
||||
|
||||
#[test]
|
||||
fn comment() {
|
||||
let s = "# comment bruh
|
||||
/* this is a multiline comment wow
|
||||
asdfasdf
|
||||
asdfasdf */
|
||||
1 + 1
|
||||
/* last one */
|
||||
";
|
||||
let comments: Vec<String> = Root::parse(s)
|
||||
.ok()
|
||||
.unwrap()
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.filter_map(|e| match e {
|
||||
rowan::NodeOrToken::Token(token) => match_ast! { match token {
|
||||
ast::Comment(it) => Some(it.text().to_string()),
|
||||
_ => None,
|
||||
}},
|
||||
rowan::NodeOrToken::Node(_) => None,
|
||||
})
|
||||
.collect();
|
||||
let expected = vec![
|
||||
" comment bruh",
|
||||
" this is a multiline comment wow\nasdfasdf\nasdfasdf ",
|
||||
" last one ",
|
||||
];
|
||||
|
||||
assert_eq!(comments, expected);
|
||||
}
|
||||
}
|
||||
|
||||
token! { #[from(TOKEN_FLOAT)] struct Float; }
|
||||
|
||||
impl Float {
|
||||
pub fn value(&self) -> Result<f64, num::ParseFloatError> {
|
||||
self.syntax().text().parse()
|
||||
}
|
||||
}
|
||||
|
||||
token! { #[from(TOKEN_INTEGER)] struct Integer; }
|
||||
|
||||
impl Integer {
|
||||
pub fn value(&self) -> Result<i64, num::ParseIntError> {
|
||||
self.syntax().text().parse()
|
||||
}
|
||||
}
|
||||
|
||||
// A literal part of a path (absolute / relative / home / search) without
|
||||
// distinguishing which concrete flavour it was taken from.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct PathContent(pub(super) SyntaxToken);
|
||||
|
||||
impl PathContent {
|
||||
/// Returns the path as a string
|
||||
pub fn text(&self) -> &str {
|
||||
self.syntax().text()
|
||||
}
|
||||
|
||||
/// Returns the kind of path token
|
||||
pub fn path_kind(&self) -> SyntaxKind {
|
||||
self.syntax().kind()
|
||||
}
|
||||
|
||||
/// Returns true if this is an absolute path
|
||||
pub fn is_absolute(&self) -> bool {
|
||||
self.path_kind() == TOKEN_PATH_ABS
|
||||
}
|
||||
|
||||
/// Returns true if this is a relative path
|
||||
pub fn is_relative(&self) -> bool {
|
||||
self.path_kind() == TOKEN_PATH_REL
|
||||
}
|
||||
|
||||
/// Returns true if this is a home-relative path
|
||||
pub fn is_home(&self) -> bool {
|
||||
self.path_kind() == TOKEN_PATH_HOME
|
||||
}
|
||||
|
||||
/// Returns true if this is a search path
|
||||
pub fn is_search(&self) -> bool {
|
||||
self.path_kind() == TOKEN_PATH_SEARCH
|
||||
}
|
||||
}
|
||||
|
||||
impl AstToken for PathContent {
|
||||
fn can_cast(kind: SyntaxKind) -> bool {
|
||||
matches!(kind, TOKEN_PATH_ABS | TOKEN_PATH_REL | TOKEN_PATH_HOME | TOKEN_PATH_SEARCH)
|
||||
}
|
||||
|
||||
fn cast(from: SyntaxToken) -> Option<Self> {
|
||||
if Self::can_cast(from.kind()) {
|
||||
Some(Self(from))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn syntax(&self) -> &SyntaxToken {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
token! { #[from(TOKEN_STRING_CONTENT)] struct StrContent; }
|
||||
|
||||
token! { #[from(TOKEN_URI)] struct Uri; }
|
||||
285
third_party/crates/rnix-0.14.0/src/kinds.rs
vendored
Normal file
285
third_party/crates/rnix-0.14.0/src/kinds.rs
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[repr(u16)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[non_exhaustive]
|
||||
pub enum SyntaxKind {
|
||||
TOKEN_ADD,
|
||||
TOKEN_AND_AND,
|
||||
TOKEN_ASSIGN,
|
||||
TOKEN_ASSERT,
|
||||
TOKEN_AT,
|
||||
TOKEN_COLON,
|
||||
TOKEN_COMMA,
|
||||
TOKEN_COMMENT,
|
||||
TOKEN_CONCAT,
|
||||
TOKEN_CUR_POS,
|
||||
TOKEN_DIV,
|
||||
TOKEN_DOT,
|
||||
TOKEN_ELLIPSIS,
|
||||
TOKEN_ELSE,
|
||||
TOKEN_EQUAL,
|
||||
TOKEN_ERROR,
|
||||
TOKEN_FLOAT,
|
||||
TOKEN_IDENT,
|
||||
TOKEN_IF,
|
||||
TOKEN_IMPLICATION,
|
||||
TOKEN_IN,
|
||||
TOKEN_INHERIT,
|
||||
TOKEN_INTEGER,
|
||||
TOKEN_INTERPOL_END,
|
||||
TOKEN_INTERPOL_START,
|
||||
TOKEN_INVERT,
|
||||
TOKEN_L_BRACE,
|
||||
TOKEN_L_BRACK,
|
||||
TOKEN_L_PAREN,
|
||||
TOKEN_LESS,
|
||||
TOKEN_LESS_OR_EQ,
|
||||
TOKEN_LET,
|
||||
TOKEN_MORE,
|
||||
TOKEN_MORE_OR_EQ,
|
||||
TOKEN_MUL,
|
||||
TOKEN_NOT_EQUAL,
|
||||
TOKEN_OR,
|
||||
TOKEN_OR_OR,
|
||||
TOKEN_PATH_ABS,
|
||||
TOKEN_PATH_HOME,
|
||||
TOKEN_PATH_REL,
|
||||
TOKEN_PATH_SEARCH,
|
||||
TOKEN_PIPE_LEFT,
|
||||
TOKEN_PIPE_RIGHT,
|
||||
TOKEN_QUESTION,
|
||||
TOKEN_R_BRACE,
|
||||
TOKEN_R_BRACK,
|
||||
TOKEN_R_PAREN,
|
||||
TOKEN_REC,
|
||||
TOKEN_SEMICOLON,
|
||||
TOKEN_STRING_CONTENT,
|
||||
TOKEN_STRING_END,
|
||||
TOKEN_STRING_START,
|
||||
TOKEN_SUB,
|
||||
TOKEN_THEN,
|
||||
TOKEN_UPDATE,
|
||||
TOKEN_URI,
|
||||
TOKEN_WHITESPACE,
|
||||
TOKEN_WITH,
|
||||
|
||||
NODE_APPLY,
|
||||
NODE_ASSERT,
|
||||
NODE_ATTR_SET,
|
||||
NODE_ATTRPATH,
|
||||
NODE_ATTRPATH_VALUE,
|
||||
NODE_BIN_OP,
|
||||
NODE_CUR_POS,
|
||||
NODE_DYNAMIC,
|
||||
NODE_ERROR,
|
||||
// Attrpath existence check: foo ? bar.${baz}."bux"
|
||||
NODE_HAS_ATTR,
|
||||
NODE_IDENT,
|
||||
NODE_IDENT_PARAM,
|
||||
NODE_IF_ELSE,
|
||||
NODE_INHERIT,
|
||||
NODE_INHERIT_FROM,
|
||||
NODE_INTERPOL,
|
||||
NODE_LAMBDA,
|
||||
// An old let { x = 92; body = x; } syntax
|
||||
NODE_LEGACY_LET,
|
||||
NODE_LET_IN,
|
||||
NODE_LIST,
|
||||
NODE_LITERAL,
|
||||
NODE_PAREN,
|
||||
NODE_PAT_BIND,
|
||||
NODE_PAT_ENTRY,
|
||||
NODE_PATTERN,
|
||||
NODE_PATH_ABS,
|
||||
NODE_PATH_HOME,
|
||||
NODE_PATH_REL,
|
||||
NODE_PATH_SEARCH,
|
||||
NODE_ROOT,
|
||||
NODE_SELECT,
|
||||
NODE_STRING,
|
||||
NODE_UNARY_OP,
|
||||
NODE_WITH,
|
||||
}
|
||||
use SyntaxKind::*;
|
||||
|
||||
/// Maximum valid discriminant value for SyntaxKind
|
||||
pub(crate) const SYNTAX_KIND_MAX: u16 = NODE_WITH as u16;
|
||||
|
||||
/// Error returned when parsing a string into a `SyntaxKind` fails.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ParseSyntaxKindError;
|
||||
|
||||
impl std::fmt::Display for ParseSyntaxKindError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "invalid SyntaxKind")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ParseSyntaxKindError {}
|
||||
|
||||
impl std::str::FromStr for SyntaxKind {
|
||||
type Err = ParseSyntaxKindError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"TOKEN_ADD" => Ok(TOKEN_ADD),
|
||||
"TOKEN_AND_AND" => Ok(TOKEN_AND_AND),
|
||||
"TOKEN_ASSIGN" => Ok(TOKEN_ASSIGN),
|
||||
"TOKEN_ASSERT" => Ok(TOKEN_ASSERT),
|
||||
"TOKEN_AT" => Ok(TOKEN_AT),
|
||||
"TOKEN_COLON" => Ok(TOKEN_COLON),
|
||||
"TOKEN_COMMA" => Ok(TOKEN_COMMA),
|
||||
"TOKEN_COMMENT" => Ok(TOKEN_COMMENT),
|
||||
"TOKEN_CONCAT" => Ok(TOKEN_CONCAT),
|
||||
"TOKEN_CUR_POS" => Ok(TOKEN_CUR_POS),
|
||||
"TOKEN_DIV" => Ok(TOKEN_DIV),
|
||||
"TOKEN_DOT" => Ok(TOKEN_DOT),
|
||||
"TOKEN_ELLIPSIS" => Ok(TOKEN_ELLIPSIS),
|
||||
"TOKEN_ELSE" => Ok(TOKEN_ELSE),
|
||||
"TOKEN_EQUAL" => Ok(TOKEN_EQUAL),
|
||||
"TOKEN_ERROR" => Ok(TOKEN_ERROR),
|
||||
"TOKEN_FLOAT" => Ok(TOKEN_FLOAT),
|
||||
"TOKEN_IDENT" => Ok(TOKEN_IDENT),
|
||||
"TOKEN_IF" => Ok(TOKEN_IF),
|
||||
"TOKEN_IMPLICATION" => Ok(TOKEN_IMPLICATION),
|
||||
"TOKEN_IN" => Ok(TOKEN_IN),
|
||||
"TOKEN_INHERIT" => Ok(TOKEN_INHERIT),
|
||||
"TOKEN_INTEGER" => Ok(TOKEN_INTEGER),
|
||||
"TOKEN_INTERPOL_END" => Ok(TOKEN_INTERPOL_END),
|
||||
"TOKEN_INTERPOL_START" => Ok(TOKEN_INTERPOL_START),
|
||||
"TOKEN_INVERT" => Ok(TOKEN_INVERT),
|
||||
"TOKEN_L_BRACE" => Ok(TOKEN_L_BRACE),
|
||||
"TOKEN_L_BRACK" => Ok(TOKEN_L_BRACK),
|
||||
"TOKEN_L_PAREN" => Ok(TOKEN_L_PAREN),
|
||||
"TOKEN_LESS" => Ok(TOKEN_LESS),
|
||||
"TOKEN_LESS_OR_EQ" => Ok(TOKEN_LESS_OR_EQ),
|
||||
"TOKEN_LET" => Ok(TOKEN_LET),
|
||||
"TOKEN_MORE" => Ok(TOKEN_MORE),
|
||||
"TOKEN_MORE_OR_EQ" => Ok(TOKEN_MORE_OR_EQ),
|
||||
"TOKEN_MUL" => Ok(TOKEN_MUL),
|
||||
"TOKEN_NOT_EQUAL" => Ok(TOKEN_NOT_EQUAL),
|
||||
"TOKEN_OR" => Ok(TOKEN_OR),
|
||||
"TOKEN_OR_OR" => Ok(TOKEN_OR_OR),
|
||||
"TOKEN_PATH_ABS" => Ok(TOKEN_PATH_ABS),
|
||||
"TOKEN_PATH_HOME" => Ok(TOKEN_PATH_HOME),
|
||||
"TOKEN_PATH_REL" => Ok(TOKEN_PATH_REL),
|
||||
"TOKEN_PATH_SEARCH" => Ok(TOKEN_PATH_SEARCH),
|
||||
"TOKEN_PIPE_LEFT" => Ok(TOKEN_PIPE_LEFT),
|
||||
"TOKEN_PIPE_RIGHT" => Ok(TOKEN_PIPE_RIGHT),
|
||||
"TOKEN_QUESTION" => Ok(TOKEN_QUESTION),
|
||||
"TOKEN_R_BRACE" => Ok(TOKEN_R_BRACE),
|
||||
"TOKEN_R_BRACK" => Ok(TOKEN_R_BRACK),
|
||||
"TOKEN_R_PAREN" => Ok(TOKEN_R_PAREN),
|
||||
"TOKEN_REC" => Ok(TOKEN_REC),
|
||||
"TOKEN_SEMICOLON" => Ok(TOKEN_SEMICOLON),
|
||||
"TOKEN_STRING_CONTENT" => Ok(TOKEN_STRING_CONTENT),
|
||||
"TOKEN_STRING_END" => Ok(TOKEN_STRING_END),
|
||||
"TOKEN_STRING_START" => Ok(TOKEN_STRING_START),
|
||||
"TOKEN_SUB" => Ok(TOKEN_SUB),
|
||||
"TOKEN_THEN" => Ok(TOKEN_THEN),
|
||||
"TOKEN_UPDATE" => Ok(TOKEN_UPDATE),
|
||||
"TOKEN_URI" => Ok(TOKEN_URI),
|
||||
"TOKEN_WHITESPACE" => Ok(TOKEN_WHITESPACE),
|
||||
"TOKEN_WITH" => Ok(TOKEN_WITH),
|
||||
|
||||
"NODE_APPLY" => Ok(NODE_APPLY),
|
||||
"NODE_ASSERT" => Ok(NODE_ASSERT),
|
||||
"NODE_ATTR_SET" => Ok(NODE_ATTR_SET),
|
||||
"NODE_ATTRPATH" => Ok(NODE_ATTRPATH),
|
||||
"NODE_ATTRPATH_VALUE" => Ok(NODE_ATTRPATH_VALUE),
|
||||
"NODE_BIN_OP" => Ok(NODE_BIN_OP),
|
||||
"NODE_CUR_POS" => Ok(NODE_CUR_POS),
|
||||
"NODE_DYNAMIC" => Ok(NODE_DYNAMIC),
|
||||
"NODE_ERROR" => Ok(NODE_ERROR),
|
||||
"NODE_HAS_ATTR" => Ok(NODE_HAS_ATTR),
|
||||
"NODE_IDENT" => Ok(NODE_IDENT),
|
||||
"NODE_IDENT_PARAM" => Ok(NODE_IDENT_PARAM),
|
||||
"NODE_IF_ELSE" => Ok(NODE_IF_ELSE),
|
||||
"NODE_INHERIT" => Ok(NODE_INHERIT),
|
||||
"NODE_INHERIT_FROM" => Ok(NODE_INHERIT_FROM),
|
||||
"NODE_INTERPOL" => Ok(NODE_INTERPOL),
|
||||
"NODE_LAMBDA" => Ok(NODE_LAMBDA),
|
||||
"NODE_LEGACY_LET" => Ok(NODE_LEGACY_LET),
|
||||
"NODE_LET_IN" => Ok(NODE_LET_IN),
|
||||
"NODE_LIST" => Ok(NODE_LIST),
|
||||
"NODE_LITERAL" => Ok(NODE_LITERAL),
|
||||
"NODE_PAREN" => Ok(NODE_PAREN),
|
||||
"NODE_PAT_BIND" => Ok(NODE_PAT_BIND),
|
||||
"NODE_PAT_ENTRY" => Ok(NODE_PAT_ENTRY),
|
||||
"NODE_PATTERN" => Ok(NODE_PATTERN),
|
||||
"NODE_PATH_ABS" => Ok(NODE_PATH_ABS),
|
||||
"NODE_PATH_HOME" => Ok(NODE_PATH_HOME),
|
||||
"NODE_PATH_REL" => Ok(NODE_PATH_REL),
|
||||
"NODE_PATH_SEARCH" => Ok(NODE_PATH_SEARCH),
|
||||
"NODE_ROOT" => Ok(NODE_ROOT),
|
||||
"NODE_SELECT" => Ok(NODE_SELECT),
|
||||
"NODE_STRING" => Ok(NODE_STRING),
|
||||
"NODE_UNARY_OP" => Ok(NODE_UNARY_OP),
|
||||
"NODE_WITH" => Ok(NODE_WITH),
|
||||
|
||||
_ => Err(ParseSyntaxKindError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SyntaxKind {
|
||||
/// Returns true if this token is a literal, such as an integer or a string
|
||||
pub fn is_literal(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
TOKEN_FLOAT
|
||||
| TOKEN_INTEGER
|
||||
| TOKEN_PATH_ABS
|
||||
| TOKEN_PATH_REL
|
||||
| TOKEN_PATH_HOME
|
||||
| TOKEN_PATH_SEARCH
|
||||
| TOKEN_URI
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns true if this token should be used as a function argument.
|
||||
/// ```ignore
|
||||
/// Example:
|
||||
/// add 1 2 + 3
|
||||
/// ^ ^ ^ ^
|
||||
/// | | | +- false
|
||||
/// | | +- true
|
||||
/// | +- true
|
||||
/// +- true
|
||||
/// ```
|
||||
pub fn is_fn_arg(self) -> bool {
|
||||
match self {
|
||||
// NB: the tokenizer always emits TOKEN_IDENT for __curPos;
|
||||
// TOKEN_CUR_POS is included for completeness but cannot
|
||||
// currently be produced by the tokenizer.
|
||||
TOKEN_REC | TOKEN_L_BRACE | TOKEN_L_BRACK | TOKEN_L_PAREN | TOKEN_STRING_START
|
||||
| TOKEN_IDENT | TOKEN_CUR_POS => true,
|
||||
_ => self.is_literal(),
|
||||
}
|
||||
}
|
||||
/// Returns true if this token is a comment, whitespace, or similar, and
|
||||
/// should be skipped over by the parser.
|
||||
pub fn is_trivia(self) -> bool {
|
||||
matches!(self, TOKEN_COMMENT | TOKEN_WHITESPACE)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn from_str_valid() {
|
||||
assert_eq!(SyntaxKind::from_str("TOKEN_COMMENT").unwrap(), TOKEN_COMMENT);
|
||||
assert_eq!(SyntaxKind::from_str("NODE_ROOT").unwrap(), NODE_ROOT);
|
||||
assert_eq!(SyntaxKind::from_str("NODE_HAS_ATTR").unwrap(), NODE_HAS_ATTR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str_invalid() {
|
||||
assert!(SyntaxKind::from_str("INVALID").is_err());
|
||||
assert!(SyntaxKind::from_str("").is_err());
|
||||
assert!(SyntaxKind::from_str("token_comment").is_err()); // case sensitive
|
||||
}
|
||||
}
|
||||
111
third_party/crates/rnix-0.14.0/src/lib.rs
vendored
Normal file
111
third_party/crates/rnix-0.14.0/src/lib.rs
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
pub mod ast;
|
||||
mod kinds;
|
||||
mod parser;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod token_set;
|
||||
mod tokenizer;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use self::kinds::SYNTAX_KIND_MAX;
|
||||
pub use self::{kinds::ParseSyntaxKindError, kinds::SyntaxKind, tokenizer::tokenize};
|
||||
|
||||
use ast::AstNode;
|
||||
pub use parser::ParseError;
|
||||
use rowan::GreenNode;
|
||||
pub use rowan::{NodeOrToken, TextRange, TextSize, TokenAtOffset, WalkEvent};
|
||||
pub(crate) use token_set::TokenSet;
|
||||
pub use tokenizer::Token;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum NixLanguage {}
|
||||
|
||||
impl rowan::Language for NixLanguage {
|
||||
type Kind = SyntaxKind;
|
||||
fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
|
||||
let discriminant: u16 = raw.0;
|
||||
assert!(discriminant <= SYNTAX_KIND_MAX);
|
||||
unsafe { std::mem::transmute::<u16, SyntaxKind>(discriminant) }
|
||||
}
|
||||
fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
|
||||
rowan::SyntaxKind(kind as u16)
|
||||
}
|
||||
}
|
||||
|
||||
pub type SyntaxNode = rowan::SyntaxNode<NixLanguage>;
|
||||
pub type SyntaxToken = rowan::SyntaxToken<NixLanguage>;
|
||||
pub type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;
|
||||
pub type SyntaxElementChildren = rowan::SyntaxElementChildren<NixLanguage>;
|
||||
pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<NixLanguage>;
|
||||
|
||||
pub use ast::Root;
|
||||
|
||||
impl Root {
|
||||
pub fn parse(s: &str) -> Parse<Root> {
|
||||
let (green, errors) = parser::parse(tokenize(s));
|
||||
Parse { green, errors, _ty: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of a parse
|
||||
#[derive(Clone)]
|
||||
pub struct Parse<T> {
|
||||
green: GreenNode,
|
||||
errors: Vec<ParseError>,
|
||||
_ty: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<T> Parse<T> {
|
||||
pub fn syntax(&self) -> SyntaxNode {
|
||||
SyntaxNode::new_root(self.green.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AstNode> Parse<T> {
|
||||
pub fn tree(&self) -> T {
|
||||
T::cast(self.syntax()).unwrap()
|
||||
}
|
||||
|
||||
/// Return all errors in the tree, if any
|
||||
pub fn errors(&self) -> &[ParseError] {
|
||||
&self.errors
|
||||
}
|
||||
|
||||
/// Either return the first error in the tree, or if there are none return self
|
||||
pub fn ok(self) -> Result<T, ParseError> {
|
||||
if let Some(err) = self.errors().first() {
|
||||
return Err(err.clone());
|
||||
}
|
||||
Ok(self.tree())
|
||||
}
|
||||
}
|
||||
|
||||
/// Matches a `SyntaxNode` against an `ast` type.
|
||||
///
|
||||
/// # Example:
|
||||
///
|
||||
/// ```ignore
|
||||
/// match_ast! {
|
||||
/// match node {
|
||||
/// ast::Apply(it) => { ... },
|
||||
/// ast::Assert(it) => { ... },
|
||||
/// ast::IfElse(it) => { ... },
|
||||
/// _ => None,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! match_ast {
|
||||
(match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
|
||||
|
||||
(match ($node:expr) {
|
||||
$( ast::$ast:ident($it:pat) => $res:expr, )*
|
||||
_ => $catch_all:expr $(,)?
|
||||
}) => {{
|
||||
$( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
|
||||
{ $catch_all }
|
||||
}};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user