cargo vendor

This commit is contained in:
Alexander Burmatov 2024-09-06 01:05:13 +03:00
parent e90948a803
commit 0bb97dbe0f
9691 changed files with 3514284 additions and 847974 deletions

1176
pve-rs/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"ef9fa958318e442f1da7d204494cefec75c144aa6d5d5c93b0a5d6fcdf4ef6c6","Cargo.lock":"20b23c454fc3127f08a1bcd2864bbf029793759e6411fba24d44d8f4b7831ad0","Cargo.toml":"d0f15fde73d42bdf00e93f960dff908447225bede9364cb1659e44740a536c04","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"76d28502bd2e83f6a9e3576bd45e9a7fe5308448c4b5384b0d249515b5f67a5c","bench.plot.r":"6a5d7a4d36ed6b3d9919be703a479bef47698bf947818b483ff03951df2d4e01","benchmark.sh":"b35f89b1ca2c1dc0476cdd07f0284b72d41920d1c7b6054072f50ffba296d78d","coverage.sh":"4677e81922d08a82e83068a911717a247c66af12e559f37b78b6be3337ac9f07","examples/addr2line.rs":"3c5eb5a6726634df6cf53e4d67ee9f90c9ac09838303947f45c3bea1e84548b5","rustfmt.toml":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","src/builtin_split_dwarf_loader.rs":"dc6979de81b35f82e97275e6be27ec61f3c4225ea10574a9e031813e00185174","src/function.rs":"68f047e0c78afe18ad165db255c8254ee74c35cd6df0cc07e400252981f661ed","src/lazy.rs":"0bf23f7098f1902f181e43c2ffa82a3f86df2c0dbcb9bc0ebce6a0168dd8b060","src/lib.rs":"9d6531f71fd138d31cc7596db9ab234198d0895a21ea9cb116434c19ec78b660","tests/correctness.rs":"4081f8019535305e3aa254c6a4e1436272dd873f9717c687ca0e66ea8d5871ed","tests/output_equivalence.rs":"b2cd7c59fa55808a2e66e9fe7f160d846867e3ecefe22c22a818f822c3c41f23","tests/parse.rs":"c2f7362e4679c1b4803b12ec6e8dca6da96aed7273fd210a857524a4182c30e7"},"package":"8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"} {"files":{"CHANGELOG.md":"ce94cdbac54bd8018cbbb56b19c4d140f1ceb497c6457b7c1a83c1f2866e20d5","Cargo.lock":"d48e85d4c679f6a893ac8045649bd95715640ee432bae12cddbb10d218383277","Cargo.toml":"9f8853132e41d62586629fe1006d4767330ba9d270fe18c2b564a02cbd7610f5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"e99d88d232bf57d70f0fb87f6b496d44b6653f99f8a63d250a54c61ea4bcde40","README.md":"76d28502bd2e83f6a9e3576bd45e9a7fe5308448c4b5384b0d249515b5f67a5c","examples/addr2line.rs":"3c5eb5a6726634df6cf53e4d67ee9f90c9ac09838303947f45c3bea1e84548b5","rustfmt.toml":"01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b","src/builtin_split_dwarf_loader.rs":"b1e7efd9fdb9f494a6e9eb57a71596fc2d9cd6d46e2f237a01c91f8ba8115884","src/function.rs":"68f047e0c78afe18ad165db255c8254ee74c35cd6df0cc07e400252981f661ed","src/lazy.rs":"0bf23f7098f1902f181e43c2ffa82a3f86df2c0dbcb9bc0ebce6a0168dd8b060","src/lib.rs":"541e363ea28ac6705ef591b60792e6b29a5beeeb1822bf711d95bdf40283be50","tests/correctness.rs":"5b765fb8f84bb466baefb990406a50712a1b77c25f2a414cd070e6a77a9437b2","tests/output_equivalence.rs":"b2cd7c59fa55808a2e66e9fe7f160d846867e3ecefe22c22a818f822c3c41f23","tests/parse.rs":"e9bbffbb56de16b2f0bda3b0ab294e3e14816a83c3c1adf74676211ee80c34aa"},"package":"6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"}

View File

@ -2,6 +2,14 @@
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
## 0.22.0 (2024/04/11)
### Breaking changes
* Updated `gimli` and `object` dependencies.
--------------------------------------------------------------------------------
## 0.21.0 (2023/08/12) ## 0.21.0 (2023/08/12)
### Breaking changes ### Breaking changes

433
pve-rs/vendor/addr2line/Cargo.lock generated vendored
View File

@ -4,16 +4,16 @@ version = 3
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.19.0" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [ dependencies = [
"gimli 0.27.2", "gimli 0.28.1",
] ]
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.21.0" version = "0.22.0"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"clap", "clap",
@ -21,10 +21,10 @@ dependencies = [
"cpp_demangle", "cpp_demangle",
"fallible-iterator", "fallible-iterator",
"findshlibs", "findshlibs",
"gimli 0.28.0", "gimli 0.29.0",
"libtest-mimic", "libtest-mimic",
"memmap2", "memmap2",
"object 0.32.0", "object 0.35.0",
"rustc-demangle", "rustc-demangle",
"rustc-std-workspace-alloc", "rustc-std-workspace-alloc",
"rustc-std-workspace-core", "rustc-std-workspace-core",
@ -40,91 +40,84 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.3.2" version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"anstyle-parse", "anstyle-parse",
"anstyle-query", "anstyle-query",
"anstyle-wincon", "anstyle-wincon",
"colorchoice", "colorchoice",
"is-terminal",
"utf8parse", "utf8parse",
] ]
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.1" version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
[[package]] [[package]]
name = "anstyle-parse" name = "anstyle-parse"
version = "0.2.1" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
dependencies = [ dependencies = [
"utf8parse", "utf8parse",
] ]
[[package]] [[package]]
name = "anstyle-query" name = "anstyle-query"
version = "1.0.0" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
name = "anstyle-wincon" name = "anstyle-wincon"
version = "1.0.2" version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.67" version = "0.3.71"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
dependencies = [ dependencies = [
"addr2line 0.19.0", "addr2line 0.21.0",
"cc", "cc",
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object 0.30.3", "object 0.32.2",
"rustc-demangle", "rustc-demangle",
] ]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.79" version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -134,20 +127,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.3.21" version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
"once_cell",
] ]
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.3.21" version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -158,21 +150,21 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.3.12" version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.58",
] ]
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.5.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
@ -182,47 +174,56 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]] [[package]]
name = "compiler_builtins" name = "compiler_builtins"
version = "0.1.91" version = "0.1.109"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571298a3cce7e2afbd3d61abb91a18667d5ab25993ec577a88ee8ac45f00cc3a" checksum = "f11973008a8cf741fe6d22f339eba21fd0ca81e2760a769ba8243ed6c21edd7e"
[[package]] [[package]]
name = "cpp_demangle" name = "cpp_demangle"
version = "0.4.1" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c76f98bdfc7f66172e6c7065f981ebb576ffc903fe4c0561d9f0c2509226dc6" checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.3.2" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]] [[package]]
name = "errno" name = "derive_more"
version = "0.3.2" version = "0.99.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
dependencies = [ dependencies = [
"errno-dragonfly", "proc-macro2",
"libc", "quote",
"windows-sys", "syn 1.0.109",
] ]
[[package]] [[package]]
name = "errno-dragonfly" name = "errno"
version = "0.1.2" version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
dependencies = [ dependencies = [
"cc",
"libc", "libc",
"windows-sys 0.52.0",
]
[[package]]
name = "escape8259"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba4f4911e3666fcd7826997b4745c8224295a6f3072f1418c3067b97a67557ee"
dependencies = [
"rustversion",
] ]
[[package]] [[package]]
@ -245,9 +246,9 @@ dependencies = [
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.25" version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide",
@ -255,15 +256,15 @@ dependencies = [
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.27.2" version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.28.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"fallible-iterator", "fallible-iterator",
@ -274,46 +275,15 @@ dependencies = [
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.2.6" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "io-lifetimes"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [
"hermit-abi 0.3.2",
"libc",
"windows-sys",
]
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi 0.3.2",
"rustix 0.38.8",
"windows-sys",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
@ -323,116 +293,105 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.147" version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]] [[package]]
name = "libtest-mimic" name = "libtest-mimic"
version = "0.6.1" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d8de370f98a6cb8a4606618e53e802f93b094ddec0f96988eaec2c27e6e9ce7" checksum = "fefdf21230d6143476a28adbee3d930e2b68a3d56443c777cae3fe9340eebff9"
dependencies = [ dependencies = [
"clap", "clap",
"escape8259",
"termcolor", "termcolor",
"threadpool", "threadpool",
] ]
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.3.8" version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.5.0" version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]] [[package]]
name = "memmap2" name = "memmap2"
version = "0.5.10" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.6.2" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [ dependencies = [
"adler", "adler",
] ]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.15.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [ dependencies = [
"hermit-abi 0.2.6", "hermit-abi",
"libc", "libc",
] ]
[[package]] [[package]]
name = "object" name = "object"
version = "0.30.3" version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]] [[package]]
name = "object" name = "object"
version = "0.32.0" version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
dependencies = [ dependencies = [
"flate2", "flate2",
"memchr", "memchr",
"ruzstd", "ruzstd",
] ]
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.56" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.26" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.22" version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]] [[package]]
name = "rustc-std-workspace-alloc" name = "rustc-std-workspace-alloc"
@ -448,47 +407,39 @@ checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.37.23" version = "0.38.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags",
"errno", "errno",
"io-lifetimes",
"libc", "libc",
"linux-raw-sys 0.3.8", "linux-raw-sys",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
name = "rustix" name = "rustversion"
version = "0.38.8" version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys 0.4.5",
"windows-sys",
]
[[package]] [[package]]
name = "ruzstd" name = "ruzstd"
version = "0.4.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc" checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"thiserror-core", "derive_more",
"twox-hash", "twox-hash",
] ]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.10.0" version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
@ -504,9 +455,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "syn" name = "syn"
@ -521,9 +472,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.15" version = "2.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -532,41 +483,21 @@ dependencies = [
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.2.0" version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]] [[package]]
name = "terminal_size" name = "terminal_size"
version = "0.2.6" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
dependencies = [ dependencies = [
"rustix 0.37.23", "rustix",
"windows-sys", "windows-sys 0.48.0",
]
[[package]]
name = "thiserror-core"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497"
dependencies = [
"thiserror-core-impl",
]
[[package]]
name = "thiserror-core-impl"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
] ]
[[package]] [[package]]
@ -596,9 +527,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.8" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
@ -624,9 +555,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.5" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [ dependencies = [
"winapi", "winapi",
] ]
@ -643,62 +574,128 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.4",
] ]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.48.1" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.48.5",
"windows_i686_gnu", "windows_i686_gnu 0.48.5",
"windows_i686_msvc", "windows_i686_msvc 0.48.5",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
] ]
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.48.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.0" version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"

View File

@ -13,11 +13,13 @@
edition = "2018" edition = "2018"
rust-version = "1.65" rust-version = "1.65"
name = "addr2line" name = "addr2line"
version = "0.21.0" version = "0.22.0"
exclude = [ exclude = [
"/benches/*", "/benches/*",
"/fixtures/*", "/fixtures/*",
".github", ".github",
"*.sh",
"*.r",
] ]
description = "A cross-platform symbolication library written in Rust, using `gimli`" description = "A cross-platform symbolication library written in Rust, using `gimli`"
documentation = "https://docs.rs/addr2line" documentation = "https://docs.rs/addr2line"
@ -35,10 +37,10 @@ repository = "https://github.com/gimli-rs/addr2line"
[profile.bench] [profile.bench]
codegen-units = 1 codegen-units = 1
debug = true debug = 2
[profile.release] [profile.release]
debug = true debug = 2
[[example]] [[example]]
name = "addr2line" name = "addr2line"
@ -83,16 +85,16 @@ optional = true
default-features = false default-features = false
[dependencies.gimli] [dependencies.gimli]
version = "0.28.0" version = "0.29.0"
features = ["read"] features = ["read"]
default-features = false default-features = false
[dependencies.memmap2] [dependencies.memmap2]
version = "0.5.5" version = "0.9.4"
optional = true optional = true
[dependencies.object] [dependencies.object]
version = "0.32.0" version = "0.35.0"
features = ["read"] features = ["read"]
optional = true optional = true
default-features = false default-features = false
@ -117,7 +119,7 @@ features = ["wrap_help"]
version = "0.10" version = "0.10"
[dev-dependencies.libtest-mimic] [dev-dependencies.libtest-mimic]
version = "0.6.1" version = "0.7.2"
[dev-dependencies.typed-arena] [dev-dependencies.typed-arena]
version = "2" version = "2"

View File

@ -1,23 +0,0 @@
v <- read.table(file("stdin"))
t <- data.frame(prog=v[,1], funcs=(v[,2]=="func"), time=v[,3], mem=v[,4], stringsAsFactors=FALSE)
t$prog <- as.character(t$prog)
t$prog[t$prog == "master"] <- "gimli-rs/addr2line"
t$funcs[t$funcs == TRUE] <- "With functions"
t$funcs[t$funcs == FALSE] <- "File/line only"
t$mem = t$mem / 1024.0
library(ggplot2)
p <- ggplot(data=t, aes(x=prog, y=time, fill=prog))
p <- p + geom_bar(stat = "identity")
p <- p + facet_wrap(~ funcs)
p <- p + theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank())
p <- p + ylab("time (s)") + ggtitle("addr2line runtime")
ggsave('time.png',plot=p,width=10,height=6)
p <- ggplot(data=t, aes(x=prog, y=mem, fill=prog))
p <- p + geom_bar(stat = "identity")
p <- p + facet_wrap(~ funcs)
p <- p + theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank())
p <- p + ylab("memory (kB)") + ggtitle("addr2line memory usage")
ggsave('memory.png',plot=p,width=10,height=6)

View File

@ -1,112 +0,0 @@
#!/bin/bash
if [[ $# -le 1 ]]; then
echo "Usage: $0 <executable> [<addresses>] REFS..."
exit 1
fi
target="$1"
shift
addresses=""
if [[ -e "$1" ]]; then
addresses="$1"
shift
fi
# path to "us"
# readlink -f, but more portable:
dirname=$(perl -e 'use Cwd "abs_path";print abs_path(shift)' "$(dirname "$0")")
# https://stackoverflow.com/a/2358432/472927
{
# compile all refs
pushd "$dirname" > /dev/null
# if the user has some local changes, preserve them
nstashed=$(git stash list | wc -l)
echo "==> Stashing any local modifications"
git stash --keep-index > /dev/null
popstash() {
# https://stackoverflow.com/q/24520791/472927
if [[ "$(git stash list | wc -l)" -ne "$nstashed" ]]; then
echo "==> Restoring stashed state"
git stash pop > /dev/null
fi
}
# if the user has added stuff to the index, abort
if ! git diff-index --quiet HEAD --; then
echo "Refusing to overwrite outstanding git changes"
popstash
exit 2
fi
current=$(git symbolic-ref --short HEAD)
for ref in "$@"; do
echo "==> Compiling $ref"
git checkout -q "$ref"
commit=$(git rev-parse HEAD)
fn="target/release/addr2line-$commit"
if [[ ! -e "$fn" ]]; then
cargo build --release --example addr2line
cp target/release/examples/addr2line "$fn"
fi
if [[ "$ref" != "$commit" ]]; then
ln -sfn "addr2line-$commit" target/release/addr2line-"$ref"
fi
done
git checkout -q "$current"
popstash
popd > /dev/null
# get us some addresses to look up
if [[ -z "$addresses" ]]; then
echo "==> Looking for benchmarking addresses (this may take a while)"
addresses=$(mktemp tmp.XXXXXXXXXX)
objdump -C -x --disassemble -l "$target" \
| grep -P '0[048]:' \
| awk '{print $1}' \
| sed 's/:$//' \
> "$addresses"
echo " -> Addresses stored in $addresses; you should re-use it next time"
fi
run() {
func="$1"
name="$2"
cmd="$3"
args="$4"
printf "%s\t%s\t" "$name" "$func"
if [[ "$cmd" =~ llvm-symbolizer ]]; then
/usr/bin/time -f '%e\t%M' "$cmd" $args -obj="$target" < "$addresses" 2>&1 >/dev/null
else
/usr/bin/time -f '%e\t%M' "$cmd" $args -e "$target" < "$addresses" 2>&1 >/dev/null
fi
}
# run without functions
log1=$(mktemp tmp.XXXXXXXXXX)
echo "==> Benchmarking"
run nofunc binutils addr2line >> "$log1"
#run nofunc elfutils eu-addr2line >> "$log1"
run nofunc llvm-sym llvm-symbolizer -functions=none >> "$log1"
for ref in "$@"; do
run nofunc "$ref" "$dirname/target/release/addr2line-$ref" >> "$log1"
done
cat "$log1" | column -t
# run with functions
log2=$(mktemp tmp.XXXXXXXXXX)
echo "==> Benchmarking with -f"
run func binutils addr2line "-f -i" >> "$log2"
#run func elfutils eu-addr2line "-f -i" >> "$log2"
run func llvm-sym llvm-symbolizer "-functions=linkage -demangle=0" >> "$log2"
for ref in "$@"; do
run func "$ref" "$dirname/target/release/addr2line-$ref" "-f -i" >> "$log2"
done
cat "$log2" | column -t
cat "$log2" >> "$log1"; rm "$log2"
echo "==> Plotting"
Rscript --no-readline --no-restore --no-save "$dirname/bench.plot.r" < "$log1"
echo "==> Cleaning up"
rm "$log1"
exit 0
}

View File

@ -1,5 +0,0 @@
#!/bin/sh
# Run tarpaulin and pycobertura to generate coverage.html.
cargo tarpaulin --skip-clean --out Xml
pycobertura show --format html --output coverage.html cobertura.xml

View File

@ -27,14 +27,14 @@ fn convert_path<R: gimli::Reader<Endian = gimli::RunTimeEndian>>(
Ok(PathBuf::from(s)) Ok(PathBuf::from(s))
} }
fn load_section<'data: 'file, 'file, O, R, F>( fn load_section<'data, O, R, F>(
id: gimli::SectionId, id: gimli::SectionId,
file: &'file O, file: &O,
endian: R::Endian, endian: R::Endian,
loader: &mut F, loader: &mut F,
) -> Result<R, gimli::Error> ) -> Result<R, gimli::Error>
where where
O: object::Object<'data, 'file>, O: object::Object<'data>,
R: gimli::Reader<Endian = gimli::RunTimeEndian>, R: gimli::Reader<Endian = gimli::RunTimeEndian>,
F: FnMut(Cow<'data, [u8]>, R::Endian) -> R, F: FnMut(Cow<'data, [u8]>, R::Endian) -> R,
{ {

View File

@ -203,9 +203,7 @@ impl Context<gimli::EndianRcSlice<gimli::RunTimeEndian>> {
/// Performance sensitive applications may want to use `Context::from_dwarf` /// Performance sensitive applications may want to use `Context::from_dwarf`
/// with a more specialised `gimli::Reader` implementation. /// with a more specialised `gimli::Reader` implementation.
#[inline] #[inline]
pub fn new<'data: 'file, 'file, O: object::Object<'data, 'file>>( pub fn new<'data, O: object::Object<'data>>(file: &O) -> Result<Self, Error> {
file: &'file O,
) -> Result<Self, Error> {
Self::new_with_sup(file, None) Self::new_with_sup(file, None)
} }
@ -219,9 +217,9 @@ impl Context<gimli::EndianRcSlice<gimli::RunTimeEndian>> {
/// ///
/// Performance sensitive applications may want to use `Context::from_dwarf` /// Performance sensitive applications may want to use `Context::from_dwarf`
/// with a more specialised `gimli::Reader` implementation. /// with a more specialised `gimli::Reader` implementation.
pub fn new_with_sup<'data: 'file, 'file, O: object::Object<'data, 'file>>( pub fn new_with_sup<'data, O: object::Object<'data>>(
file: &'file O, file: &O,
sup_file: Option<&'file O>, sup_file: Option<&O>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let endian = if file.is_little_endian() { let endian = if file.is_little_endian() {
gimli::RunTimeEndian::Little gimli::RunTimeEndian::Little
@ -229,13 +227,13 @@ impl Context<gimli::EndianRcSlice<gimli::RunTimeEndian>> {
gimli::RunTimeEndian::Big gimli::RunTimeEndian::Big
}; };
fn load_section<'data: 'file, 'file, O, Endian>( fn load_section<'data, O, Endian>(
id: gimli::SectionId, id: gimli::SectionId,
file: &'file O, file: &O,
endian: Endian, endian: Endian,
) -> Result<gimli::EndianRcSlice<Endian>, Error> ) -> Result<gimli::EndianRcSlice<Endian>, Error>
where where
O: object::Object<'data, 'file>, O: object::Object<'data>,
Endian: gimli::Endianity, Endian: gimli::Endianity,
{ {
use object::ObjectSection; use object::ObjectSection;

View File

@ -44,13 +44,13 @@ fn correctness() {
gimli::RunTimeEndian::Big gimli::RunTimeEndian::Big
}; };
fn load_section<'data: 'file, 'file, O, Endian>( fn load_section<'data, O, Endian>(
id: gimli::SectionId, id: gimli::SectionId,
file: &'file O, file: &O,
endian: Endian, endian: Endian,
) -> Result<gimli::EndianArcSlice<Endian>, gimli::Error> ) -> Result<gimli::EndianArcSlice<Endian>, gimli::Error>
where where
O: object::Object<'data, 'file>, O: object::Object<'data>,
Endian: gimli::Endianity, Endian: gimli::Endianity,
{ {
use object::ObjectSection; use object::ObjectSection;

View File

@ -26,7 +26,7 @@ fn with_file<F: FnOnce(&object::File<'_>)>(target: &path::Path, f: F) {
f(&file) f(&file)
} }
fn dwarf_load<'a>(object: &object::File<'a>) -> gimli::Dwarf<Cow<'a, [u8]>> { fn dwarf_load<'a>(object: &object::File<'a>) -> gimli::DwarfSections<Cow<'a, [u8]>> {
let load_section = |id: gimli::SectionId| -> Result<Cow<'a, [u8]>, gimli::Error> { let load_section = |id: gimli::SectionId| -> Result<Cow<'a, [u8]>, gimli::Error> {
use object::ObjectSection; use object::ObjectSection;
@ -36,11 +36,11 @@ fn dwarf_load<'a>(object: &object::File<'a>) -> gimli::Dwarf<Cow<'a, [u8]>> {
.unwrap_or(&[][..]); .unwrap_or(&[][..]);
Ok(Cow::Borrowed(data)) Ok(Cow::Borrowed(data))
}; };
gimli::Dwarf::load(&load_section).unwrap() gimli::DwarfSections::load(&load_section).unwrap()
} }
fn dwarf_borrow<'a>( fn dwarf_borrow<'a>(
dwarf: &'a gimli::Dwarf<Cow<'_, [u8]>>, dwarf: &'a gimli::DwarfSections<Cow<'_, [u8]>>,
) -> gimli::Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>> { ) -> gimli::Dwarf<gimli::EndianSlice<'a, gimli::LittleEndian>> {
let borrow_section: &dyn for<'b> Fn( let borrow_section: &dyn for<'b> Fn(
&'b Cow<'_, [u8]>, &'b Cow<'_, [u8]>,

View File

@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"52435caf085b428cdb6171a34f4980f52aaaf541a3dced226c92eb82f69a48a7","Cargo.toml":"56b9cca6450964cbe772b6519bc048c2f56cc80e9261de1126d789c5e1951136","LICENSE-0BSD":"861399f8c21c042b110517e76dc6b63a2b334276c8cf17412fc3c8908ca8dc17","LICENSE-APACHE":"8ada45cd9f843acf64e4722ae262c622a2b3b3007c7310ef36ac1061a30f6adb","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"cd955d5d6a49161e6f7a04df4a5963581b66ed43fd5096b2dedca8e295efe4f9","RELEASE_PROCESS.md":"a86cd10fc70f167f8d00e9e4ce0c6b4ebdfa1865058390dffd1e0ad4d3e68d9d","benches/bench.rs":"d67bef1c7f36ed300a8fbcf9d50b9dfdead1fd340bf87a4d47d99a0c1c042c04","src/algo.rs":"932c2bc591d13fe4470185125617b5aaa660a3898f23b553acc85df0bf49dded","src/lib.rs":"4acd41668fe30daffa37084e7e223f268957b816afc1864ffb3f5d6d7adf0890"},"package":"512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"}

77
pve-rs/vendor/adler2/CHANGELOG.md vendored Normal file
View File

@ -0,0 +1,77 @@
# Changelog
All notable changes to this project will be documented in this file.
---
## [2.0.0](https://github.com/Frommi/miniz_oxide/compare/1.0.2..2.0.0) - 2024-08-04
First release of adler2 - fork of adler crate as the original is unmaintained and archived
##### Changes since last version of Adler:
### Bug Fixes
- **(core)** change to rust 2021 edition, update repository info and links, update author info - ([867b115](https://github.com/Frommi/miniz_oxide/commit/867b115bad79bf62098f2acccc81bf53ec5a125d)) - oyvindln
- **(core)** simplify some code and fix benches - ([128fb9c](https://github.com/Frommi/miniz_oxide/commit/128fb9cb6cad5c3a54fb0b6c68549d80b79a1fe0)) - oyvindln
### Changelog of original adler crate
---
## [1.0.2 - 2021-02-26](https://github.com/jonas-schievink/adler/releases/tag/v1.0.2)
- Fix doctest on big-endian systems ([#9]).
[#9]: https://github.com/jonas-schievink/adler/pull/9
## [1.0.1 - 2020-11-08](https://github.com/jonas-schievink/adler/releases/tag/v1.0.1)
### Fixes
- Fix documentation on docs.rs.
## [1.0.0 - 2020-11-08](https://github.com/jonas-schievink/adler/releases/tag/v1.0.0)
### Fixes
- Fix `cargo test --no-default-features` ([#5]).
### Improvements
- Extended and clarified documentation.
- Added more rustdoc examples.
- Extended CI to test the crate with `--no-default-features`.
### Breaking Changes
- `adler32_reader` now takes its generic argument by value instead of as a `&mut`.
- Renamed `adler32_reader` to `adler32`.
## [0.2.3 - 2020-07-11](https://github.com/jonas-schievink/adler/releases/tag/v0.2.3)
- Process 4 Bytes at a time, improving performance by up to 50% ([#2]).
## [0.2.2 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.2)
- Bump MSRV to 1.31.0.
## [0.2.1 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.1)
- Add a few `#[inline]` annotations to small functions.
- Fix CI badge.
- Allow integration into libstd.
## [0.2.0 - 2020-06-27](https://github.com/jonas-schievink/adler/releases/tag/v0.2.0)
- Support `#![no_std]` when using `default-features = false`.
- Improve performance by around 7x.
- Support Rust 1.8.0.
- Improve API naming.
## [0.1.0 - 2020-06-26](https://github.com/jonas-schievink/adler/releases/tag/v0.1.0)
Initial release.
[#2]: https://github.com/jonas-schievink/adler/pull/2
[#5]: https://github.com/jonas-schievink/adler/pull/5

97
pve-rs/vendor/adler2/Cargo.toml vendored Normal file
View File

@ -0,0 +1,97 @@
# 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 = "adler2"
version = "2.0.0"
authors = [
"Jonas Schievink <jonasschievink@gmail.com>",
"oyvindln <oyvindln@users.noreply.github.com>",
]
build = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "A simple clean-room implementation of the Adler-32 checksum"
documentation = "https://docs.rs/adler2/"
readme = "README.md"
keywords = [
"checksum",
"integrity",
"hash",
"adler32",
"zlib",
]
categories = ["algorithms"]
license = "0BSD OR MIT OR Apache-2.0"
repository = "https://github.com/oyvindln/adler2"
[package.metadata.docs.rs]
rustdoc-args = ["--cfg=docsrs"]
[package.metadata.release]
no-dev-version = true
pre-release-commit-message = "Release {{version}}"
tag-message = "{{version}}"
[[package.metadata.release.pre-release-replacements]]
file = "CHANGELOG.md"
replace = """
## Unreleased
No changes.
## [{{version}} - {{date}}](https://github.com/jonas-schievink/adler/releases/tag/v{{version}})
"""
search = """
## Unreleased
"""
[[package.metadata.release.pre-release-replacements]]
file = "README.md"
replace = 'adler = "{{version}}"'
search = 'adler = "[a-z0-9\\.-]+"'
[[package.metadata.release.pre-release-replacements]]
file = "src/lib.rs"
replace = "https://docs.rs/adler/{{version}}"
search = 'https://docs.rs/adler/[a-z0-9\.-]+'
[lib]
name = "adler2"
path = "src/lib.rs"
[[bench]]
name = "bench"
path = "benches/bench.rs"
harness = false
[dependencies.compiler_builtins]
version = "0.1.2"
optional = true
[dependencies.core]
version = "1.0.0"
optional = true
package = "rustc-std-workspace-core"
[dev-dependencies.criterion]
version = "0.3.2"
[features]
default = ["std"]
rustc-dep-of-std = [
"core",
"compiler_builtins",
]
std = []

12
pve-rs/vendor/adler2/LICENSE-0BSD vendored Normal file
View File

@ -0,0 +1,12 @@
Copyright (C) Jonas Schievink <jonasschievink@gmail.com>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

201
pve-rs/vendor/adler2/LICENSE-APACHE vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/LICENSE-2.0
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
https://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
pve-rs/vendor/adler2/LICENSE-MIT vendored Normal file
View 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.

46
pve-rs/vendor/adler2/README.md vendored Normal file
View File

@ -0,0 +1,46 @@
# Adler-32 checksums for Rust
This is a fork of the adler crate as the [original](https://github.com/jonas-schievink/adler) has been archived and is no longer updated by it's author
[![crates.io](https://img.shields.io/crates/v/adler.svg)](https://crates.io/crates/adler)
[![docs.rs](https://docs.rs/adler/badge.svg)](https://docs.rs/adler/)
![CI](https://github.com/jonas-schievink/adler/workflows/CI/badge.svg)
This crate provides a simple implementation of the Adler-32 checksum, used in
the zlib compression format.
Please refer to the [changelog](CHANGELOG.md) to see what changed in the last
releases.
## Features
- Permissively licensed (0BSD) clean-room implementation.
- Zero dependencies.
- Zero `unsafe`.
- Decent performance (3-4 GB/s) (see note).
- Supports `#![no_std]` (with `default-features = false`).
## Usage
Add an entry to your `Cargo.toml`:
```toml
[dependencies]
adler2 = "2.0.0"
```
Check the [API Documentation](https://docs.rs/adler/) for how to use the
crate's functionality.
## Rust version support
Currently, this crate supports all Rust versions starting at Rust 1.56.0.
Bumping the Minimum Supported Rust Version (MSRV) is *not* considered a breaking
change, but will not be done without good reasons. The latest 3 stable Rust
versions will always be supported no matter what.
## Performance
Due to the way the algorithm works this crate and the fact that it's not possible to use explicit simd in safe rust currently, this crate benefits drastically from being compiled with newer cpu instructions enabled (using e.g ```RUSTFLAGS=-C target-feature'+sse4.1``` or ```-C target-cpu=x86-64-v2```/```-C target-cpu=x86-64-v3``` arguments depending on what cpu support is being targeted.)
Judging by the crate benchmarks, on a Ryzen 5600, compiling with SSE 4.1 (enabled in x86-64-v2 feature level) enabled can give a ~50-150% speedup, enabling the LZCNT instruction (enabled in x86-64-v3 feature level) can give a further ~50% speedup,

13
pve-rs/vendor/adler2/RELEASE_PROCESS.md vendored Normal file
View File

@ -0,0 +1,13 @@
# What to do to publish a new release
1. Ensure all notable changes are in the changelog under "Unreleased".
2. Execute `cargo release <level>` to bump version(s), tag and publish
everything. External subcommand, must be installed with `cargo install
cargo-release`.
`<level>` can be one of `major|minor|patch`. If this is the first release
(`0.1.0`), use `minor`, since the version starts out as `0.0.0`.
3. Go to the GitHub releases, edit the just-pushed tag. Copy the release notes
from the changelog.

109
pve-rs/vendor/adler2/benches/bench.rs vendored Normal file
View File

@ -0,0 +1,109 @@
extern crate adler2;
extern crate criterion;
use adler2::{adler32_slice, Adler32};
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
fn simple(c: &mut Criterion) {
{
const SIZE: usize = 100;
let mut group = c.benchmark_group("simple-100b");
group.throughput(Throughput::Bytes(SIZE as u64));
group.bench_function("zeroes-100", |bencher| {
bencher.iter(|| {
adler32_slice(&[0; SIZE]);
});
});
group.bench_function("ones-100", |bencher| {
bencher.iter(|| {
adler32_slice(&[0xff; SIZE]);
});
});
}
{
const SIZE: usize = 1024;
let mut group = c.benchmark_group("simple-1k");
group.throughput(Throughput::Bytes(SIZE as u64));
group.bench_function("zeroes-1k", |bencher| {
bencher.iter(|| {
adler32_slice(&[0; SIZE]);
});
});
group.bench_function("ones-1k", |bencher| {
bencher.iter(|| {
adler32_slice(&[0xff; SIZE]);
});
});
}
{
const SIZE: usize = 1024 * 1024;
let mut group = c.benchmark_group("simple-1m");
group.throughput(Throughput::Bytes(SIZE as u64));
group.bench_function("zeroes-1m", |bencher| {
bencher.iter(|| {
adler32_slice(&[0; SIZE]);
});
});
group.bench_function("ones-1m", |bencher| {
bencher.iter(|| {
adler32_slice(&[0xff; SIZE]);
});
});
}
}
fn chunked(c: &mut Criterion) {
const SIZE: usize = 16 * 1024 * 1024;
let data = vec![0xAB; SIZE];
let mut group = c.benchmark_group("chunked-16m");
group.throughput(Throughput::Bytes(SIZE as u64));
group.bench_function("5552", |bencher| {
bencher.iter(|| {
let mut h = Adler32::new();
for chunk in data.chunks(5552) {
h.write_slice(chunk);
}
h.checksum()
});
});
group.bench_function("8k", |bencher| {
bencher.iter(|| {
let mut h = Adler32::new();
for chunk in data.chunks(8 * 1024) {
h.write_slice(chunk);
}
h.checksum()
});
});
group.bench_function("64k", |bencher| {
bencher.iter(|| {
let mut h = Adler32::new();
for chunk in data.chunks(64 * 1024) {
h.write_slice(chunk);
}
h.checksum()
});
});
group.bench_function("1m", |bencher| {
bencher.iter(|| {
let mut h = Adler32::new();
for chunk in data.chunks(1024 * 1024) {
h.write_slice(chunk);
}
h.checksum()
});
});
}
criterion_group!(benches, simple, chunked);
criterion_main!(benches);

155
pve-rs/vendor/adler2/src/algo.rs vendored Normal file
View File

@ -0,0 +1,155 @@
use crate::Adler32;
use std::ops::{AddAssign, MulAssign, RemAssign};
impl Adler32 {
pub(crate) fn compute(&mut self, bytes: &[u8]) {
// The basic algorithm is, for every byte:
// a = (a + byte) % MOD
// b = (b + a) % MOD
// where MOD = 65521.
//
// For efficiency, we can defer the `% MOD` operations as long as neither a nor b overflows:
// - Between calls to `write`, we ensure that a and b are always in range 0..MOD.
// - We use 32-bit arithmetic in this function.
// - Therefore, a and b must not increase by more than 2^32-MOD without performing a `% MOD`
// operation.
//
// According to Wikipedia, b is calculated as follows for non-incremental checksumming:
// b = n×D1 + (n1)×D2 + (n2)×D3 + ... + Dn + n*1 (mod 65521)
// Where n is the number of bytes and Di is the i-th Byte. We need to change this to account
// for the previous values of a and b, as well as treat every input Byte as being 255:
// b_inc = n×255 + (n-1)×255 + ... + 255 + n*65520
// Or in other words:
// b_inc = n*65520 + n(n+1)/2*255
// The max chunk size is thus the largest value of n so that b_inc <= 2^32-65521.
// 2^32-65521 = n*65520 + n(n+1)/2*255
// Plugging this into an equation solver since I can't math gives n = 5552.18..., so 5552.
//
// On top of the optimization outlined above, the algorithm can also be parallelized with a
// bit more work:
//
// Note that b is a linear combination of a vector of input bytes (D1, ..., Dn).
//
// If we fix some value k<N and rewrite indices 1, ..., N as
//
// 1_1, 1_2, ..., 1_k, 2_1, ..., 2_k, ..., (N/k)_k,
//
// then we can express a and b in terms of sums of smaller sequences kb and ka:
//
// ka(j) := D1_j + D2_j + ... + D(N/k)_j where j <= k
// kb(j) := (N/k)*D1_j + (N/k-1)*D2_j + ... + D(N/k)_j where j <= k
//
// a = ka(1) + ka(2) + ... + ka(k) + 1
// b = k*(kb(1) + kb(2) + ... + kb(k)) - 1*ka(2) - ... - (k-1)*ka(k) + N
//
// We use this insight to unroll the main loop and process k=4 bytes at a time.
// The resulting code is highly amenable to SIMD acceleration, although the immediate speedups
// stem from increased pipeline parallelism rather than auto-vectorization.
//
// This technique is described in-depth (here:)[https://software.intel.com/content/www/us/\
// en/develop/articles/fast-computation-of-fletcher-checksums.html]
const MOD: u32 = 65521;
const CHUNK_SIZE: usize = 5552 * 4;
let mut a = u32::from(self.a);
let mut b = u32::from(self.b);
let mut a_vec = U32X4([0; 4]);
let mut b_vec = a_vec;
let (bytes, remainder) = bytes.split_at(bytes.len() - bytes.len() % 4);
// iterate over 4 bytes at a time
let chunk_iter = bytes.chunks_exact(CHUNK_SIZE);
let remainder_chunk = chunk_iter.remainder();
for chunk in chunk_iter {
for byte_vec in chunk.chunks_exact(4) {
let val = U32X4::from(byte_vec);
a_vec += val;
b_vec += a_vec;
}
b += CHUNK_SIZE as u32 * a;
a_vec %= MOD;
b_vec %= MOD;
b %= MOD;
}
// special-case the final chunk because it may be shorter than the rest
for byte_vec in remainder_chunk.chunks_exact(4) {
let val = U32X4::from(byte_vec);
a_vec += val;
b_vec += a_vec;
}
b += remainder_chunk.len() as u32 * a;
a_vec %= MOD;
b_vec %= MOD;
b %= MOD;
// combine the sub-sum results into the main sum
b_vec *= 4;
b_vec.0[1] += MOD - a_vec.0[1];
b_vec.0[2] += (MOD - a_vec.0[2]) * 2;
b_vec.0[3] += (MOD - a_vec.0[3]) * 3;
for &av in a_vec.0.iter() {
a += av;
}
for &bv in b_vec.0.iter() {
b += bv;
}
// iterate over the remaining few bytes in serial
for &byte in remainder.iter() {
a += u32::from(byte);
b += a;
}
self.a = (a % MOD) as u16;
self.b = (b % MOD) as u16;
}
}
#[derive(Copy, Clone)]
struct U32X4([u32; 4]);
impl U32X4 {
#[inline]
fn from(bytes: &[u8]) -> Self {
U32X4([
u32::from(bytes[0]),
u32::from(bytes[1]),
u32::from(bytes[2]),
u32::from(bytes[3]),
])
}
}
impl AddAssign<Self> for U32X4 {
#[inline]
fn add_assign(&mut self, other: Self) {
// Implement this in a primitive manner to help out the compiler a bit.
self.0[0] += other.0[0];
self.0[1] += other.0[1];
self.0[2] += other.0[2];
self.0[3] += other.0[3];
}
}
impl RemAssign<u32> for U32X4 {
#[inline]
fn rem_assign(&mut self, quotient: u32) {
self.0[0] %= quotient;
self.0[1] %= quotient;
self.0[2] %= quotient;
self.0[3] %= quotient;
}
}
impl MulAssign<u32> for U32X4 {
#[inline]
fn mul_assign(&mut self, rhs: u32) {
self.0[0] *= rhs;
self.0[1] *= rhs;
self.0[2] *= rhs;
self.0[3] *= rhs;
}
}

287
pve-rs/vendor/adler2/src/lib.rs vendored Normal file
View File

@ -0,0 +1,287 @@
//! Adler-32 checksum implementation.
//!
//! This implementation features:
//!
//! - Permissively licensed (0BSD) clean-room implementation.
//! - Zero dependencies.
//! - Zero `unsafe`.
//! - Decent performance (3-4 GB/s).
//! - `#![no_std]` support (with `default-features = false`).
#![doc(html_root_url = "https://docs.rs/adler2/2.0.0")]
// Deny a few warnings in doctests, since rustdoc `allow`s many warnings by default
#![doc(test(attr(deny(unused_imports, unused_must_use))))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_debug_implementations)]
#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate core as std;
mod algo;
use std::hash::Hasher;
#[cfg(feature = "std")]
use std::io::{self, BufRead};
/// Adler-32 checksum calculator.
///
/// An instance of this type is equivalent to an Adler-32 checksum: It can be created in the default
/// state via [`new`] (or the provided `Default` impl), or from a precalculated checksum via
/// [`from_checksum`], and the currently stored checksum can be fetched via [`checksum`].
///
/// This type also implements `Hasher`, which makes it easy to calculate Adler-32 checksums of any
/// type that implements or derives `Hash`. This also allows using Adler-32 in a `HashMap`, although
/// that is not recommended (while every checksum is a hash function, they are not necessarily a
/// good one).
///
/// # Examples
///
/// Basic, piecewise checksum calculation:
///
/// ```
/// use adler2::Adler32;
///
/// let mut adler = Adler32::new();
///
/// adler.write_slice(&[0, 1, 2]);
/// adler.write_slice(&[3, 4, 5]);
///
/// assert_eq!(adler.checksum(), 0x00290010);
/// ```
///
/// Using `Hash` to process structures:
///
/// ```
/// use std::hash::Hash;
/// use adler2::Adler32;
///
/// #[derive(Hash)]
/// struct Data {
/// byte: u8,
/// word: u16,
/// big: u64,
/// }
///
/// let mut adler = Adler32::new();
///
/// let data = Data { byte: 0x1F, word: 0xABCD, big: !0 };
/// data.hash(&mut adler);
///
/// // hash value depends on architecture endianness
/// if cfg!(target_endian = "little") {
/// assert_eq!(adler.checksum(), 0x33410990);
/// }
/// if cfg!(target_endian = "big") {
/// assert_eq!(adler.checksum(), 0x331F0990);
/// }
///
/// ```
///
/// [`new`]: #method.new
/// [`from_checksum`]: #method.from_checksum
/// [`checksum`]: #method.checksum
#[derive(Debug, Copy, Clone)]
pub struct Adler32 {
a: u16,
b: u16,
}
impl Adler32 {
/// Creates a new Adler-32 instance with default state.
#[inline]
pub fn new() -> Self {
Self::default()
}
/// Creates an `Adler32` instance from a precomputed Adler-32 checksum.
///
/// This allows resuming checksum calculation without having to keep the `Adler32` instance
/// around.
///
/// # Example
///
/// ```
/// # use adler2::Adler32;
/// let parts = [
/// "rust",
/// "acean",
/// ];
/// let whole = adler2::adler32_slice(b"rustacean");
///
/// let mut sum = Adler32::new();
/// sum.write_slice(parts[0].as_bytes());
/// let partial = sum.checksum();
///
/// // ...later
///
/// let mut sum = Adler32::from_checksum(partial);
/// sum.write_slice(parts[1].as_bytes());
/// assert_eq!(sum.checksum(), whole);
/// ```
#[inline]
pub const fn from_checksum(sum: u32) -> Self {
Adler32 {
a: sum as u16,
b: (sum >> 16) as u16,
}
}
/// Returns the calculated checksum at this point in time.
#[inline]
pub fn checksum(&self) -> u32 {
(u32::from(self.b) << 16) | u32::from(self.a)
}
/// Adds `bytes` to the checksum calculation.
///
/// If efficiency matters, this should be called with Byte slices that contain at least a few
/// thousand Bytes.
pub fn write_slice(&mut self, bytes: &[u8]) {
self.compute(bytes);
}
}
impl Default for Adler32 {
#[inline]
fn default() -> Self {
Adler32 { a: 1, b: 0 }
}
}
impl Hasher for Adler32 {
#[inline]
fn finish(&self) -> u64 {
u64::from(self.checksum())
}
fn write(&mut self, bytes: &[u8]) {
self.write_slice(bytes);
}
}
/// Calculates the Adler-32 checksum of a byte slice.
///
/// This is a convenience function around the [`Adler32`] type.
///
/// [`Adler32`]: struct.Adler32.html
pub fn adler32_slice(data: &[u8]) -> u32 {
let mut h = Adler32::new();
h.write_slice(data);
h.checksum()
}
/// Calculates the Adler-32 checksum of a `BufRead`'s contents.
///
/// The passed `BufRead` implementor will be read until it reaches EOF (or until it reports an
/// error).
///
/// If you only have a `Read` implementor, you can wrap it in `std::io::BufReader` before calling
/// this function.
///
/// # Errors
///
/// Any error returned by the reader are bubbled up by this function.
///
/// # Examples
///
/// ```no_run
/// # fn run() -> Result<(), Box<dyn std::error::Error>> {
/// use adler2::adler32;
///
/// use std::fs::File;
/// use std::io::BufReader;
///
/// let file = File::open("input.txt")?;
/// let mut file = BufReader::new(file);
///
/// adler32(&mut file)?;
/// # Ok(()) }
/// # fn main() { run().unwrap() }
/// ```
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub fn adler32<R: BufRead>(mut reader: R) -> io::Result<u32> {
let mut h = Adler32::new();
loop {
let len = {
let buf = reader.fill_buf()?;
if buf.is_empty() {
return Ok(h.checksum());
}
h.write_slice(buf);
buf.len()
};
reader.consume(len);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zeroes() {
assert_eq!(adler32_slice(&[]), 1);
assert_eq!(adler32_slice(&[0]), 1 | 1 << 16);
assert_eq!(adler32_slice(&[0, 0]), 1 | 2 << 16);
assert_eq!(adler32_slice(&[0; 100]), 0x00640001);
assert_eq!(adler32_slice(&[0; 1024]), 0x04000001);
assert_eq!(adler32_slice(&[0; 1024 * 1024]), 0x00f00001);
}
#[test]
fn ones() {
assert_eq!(adler32_slice(&[0xff; 1024]), 0x79a6fc2e);
assert_eq!(adler32_slice(&[0xff; 1024 * 1024]), 0x8e88ef11);
}
#[test]
fn mixed() {
assert_eq!(adler32_slice(&[1]), 2 | 2 << 16);
assert_eq!(adler32_slice(&[40]), 41 | 41 << 16);
assert_eq!(adler32_slice(&[0xA5; 1024 * 1024]), 0xd5009ab1);
}
/// Example calculation from https://en.wikipedia.org/wiki/Adler-32.
#[test]
fn wiki() {
assert_eq!(adler32_slice(b"Wikipedia"), 0x11E60398);
}
#[test]
fn resume() {
let mut adler = Adler32::new();
adler.write_slice(&[0xff; 1024]);
let partial = adler.checksum();
assert_eq!(partial, 0x79a6fc2e); // from above
adler.write_slice(&[0xff; 1024 * 1024 - 1024]);
assert_eq!(adler.checksum(), 0x8e88ef11); // from above
// Make sure that we can resume computing from the partial checksum via `from_checksum`.
let mut adler = Adler32::from_checksum(partial);
adler.write_slice(&[0xff; 1024 * 1024 - 1024]);
assert_eq!(adler.checksum(), 0x8e88ef11); // from above
}
#[cfg(feature = "std")]
#[test]
fn bufread() {
use std::io::BufReader;
fn test(data: &[u8], checksum: u32) {
// `BufReader` uses an 8 KB buffer, so this will test buffer refilling.
let mut buf = BufReader::new(data);
let real_sum = adler32(&mut buf).unwrap();
assert_eq!(checksum, real_sum);
}
test(&[], 1);
test(&[0; 1024], 0x04000001);
test(&[0; 1024 * 1024], 0x00f00001);
test(&[0xA5; 1024 * 1024], 0xd5009ab1);
}
}

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"b4d01c4b8a790e435dc0ab67a1ef8b6d8e39f87bec233540e247ef313737d855","COPYING":"aacc8f585552509941b8531442e43a8e3e1aabc7d92f1ff0736250b80f65361c","Cargo.toml":"2970819aad5ebe0a89647be22da6613623199255ff0d7dbb9238927ffea696f1","README.md":"85cecaf786f948c26510911416d7e0ab4c4f10367d963cad011589648084a986","license/APACHE":"65071d88cda37097d5579c272cf0db48b23acc4e2fe3ad16a5985cd714753cbc","license/MIT":"74d0d1e38a980edecb7c71d33f2056456e2cb6c37c16bd05a882d714b5e56661","src/lib.rs":"fc1294b60cbf4d9ca3f61a43b86aac9533cd6b5b87729a9bd32f7992186d1a49","src/nightly.rs":"fc84f98e2014bef66bd54671d8ec98db973fb46b80fb271d6783eb00d1f95228","src/stable/alloc/global.rs":"411208558701915ff0f7cf7ef6c64b8a3bc932944416c26fd832d03d10a76502","src/stable/alloc/mod.rs":"63db909472169a70ad5332f33f67b88e9ea361c13725c65540d7003c83d8d226","src/stable/alloc/system.rs":"7c9145f594869c3cb934e97d3eda1b0b8ed6bd8ba89b1aea7435fc6680465b6b","src/stable/boxed.rs":"2ac1c0ba02149192030460c2be123cf0614c4fb60ce6bc483cc2b62cce83c22a","src/stable/macros.rs":"ce3915ce7ee003d8790c695d70a4e77b1e63a908a5ae0825169270d0f4ab5941","src/stable/mod.rs":"fc44985d0d999e2bd52693a49bb1796451c0a9a2e6d4f7565629392a38ca54e1","src/stable/raw_vec.rs":"bc1cb45b661ae5786912d625351e6e0d33aac8e4edaf36873874184a136cd89c","src/stable/slice.rs":"14d6eb35e3557b5f78feb48fd4bea343f037e8f1f2d2707089db4dbed438b558","src/stable/vec/drain.rs":"f8209cbd76a57823f6583a84fee285727b6c00189ec299acc9f97a0829f0742f","src/stable/vec/into_iter.rs":"9b0e58c8cd6c34b3c706696cb9508c977cbfaa0eeb32d13f799a82520b5cd490","src/stable/vec/mod.rs":"19a6772a4e3053c55c83dd774d3b0154852080bb58734dd49052a4175f0b4df1","src/stable/vec/partial_eq.rs":"cb88615747b4413f26dcab206e026bbd50150bf7d97d8df174384e86151d875e","src/stable/vec/set_len_on_drop.rs":"36f2e8fdc9b0a838eb443d74bec0291d389e52bfe4f617e391d977f15e6893b5","src/stable/vec/splice.rs":"7ce9fa74764c36ab9043f7339548e96b0b68f7d1a16769c9cb066b9a538dcb14"},"package":"0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"} {"files":{"CHANGELOG.md":"886f8c688db0c22d24b650df0dc30a39d05d54d0e562c00d9574bf31cbf73251","Cargo.toml":"8c0d2ca1b5a6063aedcd462337eeb4dfb755d81e8d132fe810419689e45eef42","LICENSE-APACHE":"20fe7b00e904ed690e3b9fd6073784d3fc428141dbd10b81c01fd143d0797f58","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"7bf09e77c1d8e9292992b717d88e33d031439aa31dc9e7bb617464270519b051","src/lib.rs":"c937309febe24f97bc637650137311d5b8097b8574b0e973f4d6fb591c3448f7","src/nightly.rs":"fcff4d236e23bc95b1ce2c00140807ba3698cc01233d910d65d74986bb36f161","src/stable/alloc/global.rs":"14836ad7d73a364474fc153b24a1f17ad0e60a69b90a8721dc1059eada8bf869","src/stable/alloc/mod.rs":"866dafd3984dd246e381d8ad1c2b3e02a60c3421b598ca493aa83f9b6422608d","src/stable/alloc/system.rs":"db5d5bf088eecac3fc5ff1281e1bf26ca36dd38f13cd52c49d95ff1bab064254","src/stable/boxed.rs":"8b9b7f4cebbc1629c478dce0dd8227db16508e1383f24490d32eab7aeb3a0cea","src/stable/macros.rs":"74490796a766338d0163f40a37612cd9ea2de58ae3d8e9abf6c7bcf81d9be4a6","src/stable/mod.rs":"a6a724e10e4db4e3b7960c65bac803152a1115af46b898ff8a61e486365c16c7","src/stable/raw_vec.rs":"8cc0e3e4d5fd21e0e83776ff21c576cbb87b69647903ee9b8f5372f8781a7328","src/stable/slice.rs":"089263b058e6c185467bad7ad14908479e5675408fc70a8291e5dddaef36035a","src/stable/vec/drain.rs":"740cd2e0f31eeb0146bbd0f645a14fe12bacd3912f003db433ddc6b3a178461f","src/stable/vec/into_iter.rs":"88c22b09682cd90c7362d702d0501566173b2d836cf82a2b92ae11fdef5b9435","src/stable/vec/mod.rs":"1561b75d0bbcdf64f47bd7f1661088b68796f0e7e02a4e9391d8a50010b86f6b","src/stable/vec/partial_eq.rs":"9f1b18605164a62b58d9e17914d573698735de31c51ceb8bd3666e83d32df370","src/stable/vec/set_len_on_drop.rs":"561342e22a194e515cc25c9a1bcd827ca24c4db033e9e2c4266fbdd2fb16e5bc","src/stable/vec/splice.rs":"95a460b3a7b4af60fdc9ba04d3a719b61a0c11786cd2d8823d022e22c397f9c9"},"package":"5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"}

View File

@ -1,7 +1,7 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]

View File

@ -1,6 +0,0 @@
Copyright 2023 The allocator-api2 Project Developers
Licensed under the Apache License, Version 2.0, <license/LICENSE-APACHE or
http://apache.org/licenses/LICENSE-2.0> or the MIT license <license/LICENSE-MIT or
http://opensource.org/licenses/MIT>, at your option. This file may not be
copied, modified, or distributed except according to those terms.

View File

@ -12,7 +12,7 @@
[package] [package]
edition = "2018" edition = "2018"
name = "allocator-api2" name = "allocator-api2"
version = "0.2.16" version = "0.2.18"
authors = ["Zakarum <zaq.dev@icloud.com>"] authors = ["Zakarum <zaq.dev@icloud.com>"]
description = "Mirror of Rust's allocator API" description = "Mirror of Rust's allocator API"
homepage = "https://github.com/zakarumych/allocator-api2" homepage = "https://github.com/zakarumych/allocator-api2"

View File

@ -0,0 +1,176 @@
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

View 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.

View File

@ -1,53 +1,53 @@
# allocator-api2 # allocator-api2
[![crates](https://img.shields.io/crates/v/allocator-api2.svg?style=for-the-badge&label=allocator-api2)](https://crates.io/crates/allocator-api2) [![crates](https://img.shields.io/crates/v/allocator-api2.svg?style=for-the-badge&label=allocator-api2)](https://crates.io/crates/allocator-api2)
[![docs](https://img.shields.io/badge/docs.rs-allocator--api2-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white)](https://docs.rs/allocator-api2) [![docs](https://img.shields.io/badge/docs.rs-allocator--api2-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white)](https://docs.rs/allocator-api2)
[![actions](https://img.shields.io/github/actions/workflow/status/zakarumych/allocator-api2/badge.yml?branch=main&style=for-the-badge)](https://github.com/zakarumych/allocator-api2/actions/workflows/badge.yml) [![actions](https://img.shields.io/github/actions/workflow/status/zakarumych/allocator-api2/badge.yml?branch=main&style=for-the-badge)](https://github.com/zakarumych/allocator-api2/actions/workflows/badge.yml)
[![MIT/Apache](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?style=for-the-badge)](COPYING) [![MIT/Apache](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?style=for-the-badge)](COPYING)
![loc](https://img.shields.io/tokei/lines/github/zakarumych/allocator-api2?style=for-the-badge) ![loc](https://img.shields.io/tokei/lines/github/zakarumych/allocator-api2?style=for-the-badge)
This crate mirrors types and traits from Rust's unstable [`allocator_api`] This crate mirrors types and traits from Rust's unstable [`allocator_api`]
The intention of this crate is to serve as substitution for actual thing The intention of this crate is to serve as substitution for actual thing
for libs when build on stable and beta channels. for libs when build on stable and beta channels.
The target users are library authors who implement allocators or collection types The target users are library authors who implement allocators or collection types
that use allocators, or anyone else who wants using [`allocator_api`] that use allocators, or anyone else who wants using [`allocator_api`]
The crate should be frequently updated with minor version bump. The crate should be frequently updated with minor version bump.
When [`allocator_api`] is stable this crate will get version `1.0` and simply When [`allocator_api`] is stable this crate will get version `1.0` and simply
re-export from `core`, `alloc` and `std`. re-export from `core`, `alloc` and `std`.
The code is mostly verbatim copy from rust repository. The code is mostly verbatim copy from rust repository.
Mostly attributes are removed. Mostly attributes are removed.
## Usage ## Usage
This paragraph describes how to use this crate correctly to ensure This paragraph describes how to use this crate correctly to ensure
compatibility and interoperability on both stable and nightly channels. compatibility and interoperability on both stable and nightly channels.
If you are writing a library that interacts with allocators API, you can If you are writing a library that interacts with allocators API, you can
add this crate as a dependency and use the types and traits from this add this crate as a dependency and use the types and traits from this
crate instead of the ones in `core` or `alloc`. crate instead of the ones in `core` or `alloc`.
This will allow your library to compile on stable and beta channels. This will allow your library to compile on stable and beta channels.
Your library *MAY* provide a feature that will enable "allocator-api2/nightly". Your library *MAY* provide a feature that will enable "allocator-api2/nightly".
When this feature is enabled, your library *MUST* enable When this feature is enabled, your library *MUST* enable
unstable `#![feature(allocator_api)]` or it may not compile. unstable `#![feature(allocator_api)]` or it may not compile.
If feature is not provided, your library may not be compatible with the If feature is not provided, your library may not be compatible with the
rest of the users and cause compilation errors on nightly channel rest of the users and cause compilation errors on nightly channel
when some other crate enables "allocator-api2/nightly" feature. when some other crate enables "allocator-api2/nightly" feature.
## License ## License
Licensed under either of Licensed under either of
* Apache License, Version 2.0, ([license/APACHE](license/APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([license/MIT](license/MIT) or http://opensource.org/licenses/MIT) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option. at your option.
## Contributions ## Contributions
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. 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.
[`allocator_api`]: https://doc.rust-lang.org/unstable-book/library-features/allocator-api.html [`allocator_api`]: https://doc.rust-lang.org/unstable-book/library-features/allocator-api.html

View File

@ -1,13 +0,0 @@
Copyright 2023 The allocator-api2 project developers
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,25 +0,0 @@
Copyright (c) 2023 The allocator-api2 project developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,19 +1,19 @@
//! //!
//! allocator-api2 crate. //! allocator-api2 crate.
//! //!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
extern crate alloc as alloc_crate; extern crate alloc as alloc_crate;
#[cfg(not(feature = "nightly"))] #[cfg(not(feature = "nightly"))]
mod stable; mod stable;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
mod nightly; mod nightly;
#[cfg(not(feature = "nightly"))] #[cfg(not(feature = "nightly"))]
pub use self::stable::*; pub use self::stable::*;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
pub use self::nightly::*; pub use self::nightly::*;

View File

@ -1,5 +1,5 @@
#[cfg(not(feature = "alloc"))] #[cfg(not(feature = "alloc"))]
pub use core::alloc; pub use core::alloc;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use alloc_crate::{alloc, boxed, vec}; pub use alloc_crate::{alloc, boxed, vec};

View File

@ -1,188 +1,187 @@
use core::ptr::NonNull; use core::ptr::NonNull;
#[doc(inline)] use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc};
pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, handle_alloc_error, realloc};
use crate::stable::{assume, invalid_mut};
use crate::stable::{assume, invalid_mut};
use super::{AllocError, Allocator, Layout};
use super::{AllocError, Allocator, Layout};
/// The global memory allocator.
/// The global memory allocator. ///
/// /// This type implements the [`Allocator`] trait by forwarding calls
/// This type implements the [`Allocator`] trait by forwarding calls /// to the allocator registered with the `#[global_allocator]` attribute
/// to the allocator registered with the `#[global_allocator]` attribute /// if there is one, or the `std` crates default.
/// if there is one, or the `std` crates default. ///
/// /// Note: while this type is unstable, the functionality it provides can be
/// Note: while this type is unstable, the functionality it provides can be /// accessed through the [free functions in `alloc`](crate#functions).
/// accessed through the [free functions in `alloc`](crate#functions). #[derive(Copy, Clone, Default, Debug)]
#[derive(Copy, Clone, Default, Debug)] pub struct Global;
pub struct Global;
impl Global {
impl Global { #[inline(always)]
#[inline(always)] fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> { match layout.size() {
match layout.size() { 0 => Ok(unsafe {
0 => Ok(unsafe { NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( invalid_mut(layout.align()),
invalid_mut(layout.align()), 0,
0, ))
)) }),
}), // SAFETY: `layout` is non-zero in size,
// SAFETY: `layout` is non-zero in size, size => unsafe {
size => unsafe { let raw_ptr = if zeroed {
let raw_ptr = if zeroed { alloc_zeroed(layout)
alloc_zeroed(layout) } else {
} else { alloc(layout)
alloc(layout) };
}; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( ptr.as_ptr(),
ptr.as_ptr(), size,
size, )))
))) },
}, }
} }
}
// SAFETY: Same as `Allocator::grow`
// SAFETY: Same as `Allocator::grow` #[inline(always)]
#[inline(always)] unsafe fn grow_impl(
unsafe fn grow_impl( &self,
&self, ptr: NonNull<u8>,
ptr: NonNull<u8>, old_layout: Layout,
old_layout: Layout, new_layout: Layout,
new_layout: Layout, zeroed: bool,
zeroed: bool, ) -> Result<NonNull<[u8]>, AllocError> {
) -> Result<NonNull<[u8]>, AllocError> { debug_assert!(
debug_assert!( new_layout.size() >= old_layout.size(),
new_layout.size() >= old_layout.size(), "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
"`new_layout.size()` must be greater than or equal to `old_layout.size()`" );
);
match old_layout.size() {
match old_layout.size() { 0 => self.alloc_impl(new_layout, zeroed),
0 => self.alloc_impl(new_layout, zeroed),
// SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
// SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // as required by safety conditions. Other conditions must be upheld by the caller
// as required by safety conditions. Other conditions must be upheld by the caller old_size if old_layout.align() == new_layout.align() => unsafe {
old_size if old_layout.align() == new_layout.align() => unsafe { let new_size = new_layout.size();
let new_size = new_layout.size();
// `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
// `realloc` probably checks for `new_size >= old_layout.size()` or something similar. assume(new_size >= old_layout.size());
assume(new_size >= old_layout.size());
let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; if zeroed {
if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
raw_ptr.add(old_size).write_bytes(0, new_size - old_size); }
} Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( ptr.as_ptr(),
ptr.as_ptr(), new_size,
new_size, )))
))) },
},
// SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,
// SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, // both the old and new memory allocation are valid for reads and writes for `old_size`
// both the old and new memory allocation are valid for reads and writes for `old_size` // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller.
// for `dealloc` must be upheld by the caller. old_size => unsafe {
old_size => unsafe { let new_ptr = self.alloc_impl(new_layout, zeroed)?;
let new_ptr = self.alloc_impl(new_layout, zeroed)?; core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size);
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size); self.deallocate(ptr, old_layout);
self.deallocate(ptr, old_layout); Ok(new_ptr)
Ok(new_ptr) },
}, }
} }
} }
}
unsafe impl Allocator for Global {
unsafe impl Allocator for Global { #[inline(always)]
#[inline(always)] fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { self.alloc_impl(layout, false)
self.alloc_impl(layout, false) }
}
#[inline(always)]
#[inline(always)] fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { self.alloc_impl(layout, true)
self.alloc_impl(layout, true) }
}
#[inline(always)]
#[inline(always)] unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { if layout.size() != 0 {
if layout.size() != 0 { // SAFETY: `layout` is non-zero in size,
// SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller
// other conditions must be upheld by the caller unsafe { dealloc(ptr.as_ptr(), layout) }
unsafe { dealloc(ptr.as_ptr(), layout) } }
} }
}
#[inline(always)]
#[inline(always)] unsafe fn grow(
unsafe fn grow( &self,
&self, ptr: NonNull<u8>,
ptr: NonNull<u8>, old_layout: Layout,
old_layout: Layout, new_layout: Layout,
new_layout: Layout, ) -> Result<NonNull<[u8]>, AllocError> {
) -> Result<NonNull<[u8]>, AllocError> { // SAFETY: all conditions must be upheld by the caller
// SAFETY: all conditions must be upheld by the caller unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } }
}
#[inline(always)]
#[inline(always)] unsafe fn grow_zeroed(
unsafe fn grow_zeroed( &self,
&self, ptr: NonNull<u8>,
ptr: NonNull<u8>, old_layout: Layout,
old_layout: Layout, new_layout: Layout,
new_layout: Layout, ) -> Result<NonNull<[u8]>, AllocError> {
) -> Result<NonNull<[u8]>, AllocError> { // SAFETY: all conditions must be upheld by the caller
// SAFETY: all conditions must be upheld by the caller unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } }
}
#[inline(always)]
#[inline(always)] unsafe fn shrink(
unsafe fn shrink( &self,
&self, ptr: NonNull<u8>,
ptr: NonNull<u8>, old_layout: Layout,
old_layout: Layout, new_layout: Layout,
new_layout: Layout, ) -> Result<NonNull<[u8]>, AllocError> {
) -> Result<NonNull<[u8]>, AllocError> { debug_assert!(
debug_assert!( new_layout.size() <= old_layout.size(),
new_layout.size() <= old_layout.size(), "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`" );
);
match new_layout.size() {
match new_layout.size() { // SAFETY: conditions must be upheld by the caller
// SAFETY: conditions must be upheld by the caller 0 => unsafe {
0 => unsafe { self.deallocate(ptr, old_layout);
self.deallocate(ptr, old_layout); Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( invalid_mut(new_layout.align()),
invalid_mut(new_layout.align()), 0,
0, )))
))) },
},
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller new_size if old_layout.align() == new_layout.align() => unsafe {
new_size if old_layout.align() == new_layout.align() => unsafe { // `realloc` probably checks for `new_size <= old_layout.size()` or something similar.
// `realloc` probably checks for `new_size <= old_layout.size()` or something similar. assume(new_size <= old_layout.size());
assume(new_size <= old_layout.size());
let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( ptr.as_ptr(),
ptr.as_ptr(), new_size,
new_size, )))
))) },
},
// SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,
// SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, // both the old and new memory allocation are valid for reads and writes for `new_size`
// both the old and new memory allocation are valid for reads and writes for `new_size` // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // for `dealloc` must be upheld by the caller.
// for `dealloc` must be upheld by the caller. new_size => unsafe {
new_size => unsafe { let new_ptr = self.allocate(new_layout)?;
let new_ptr = self.allocate(new_layout)?; core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size);
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size); self.deallocate(ptr, old_layout);
self.deallocate(ptr, old_layout); Ok(new_ptr)
Ok(new_ptr) },
}, }
} }
} }
}

View File

@ -1,416 +1,416 @@
//! Memory allocation APIs //! Memory allocation APIs
use core::{ use core::{
fmt, fmt,
ptr::{self, NonNull}, ptr::{self, NonNull},
}; };
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod global; mod global;
#[cfg(feature = "std")] #[cfg(feature = "std")]
mod system; mod system;
pub use core::alloc::{GlobalAlloc, Layout, LayoutError}; pub use core::alloc::{GlobalAlloc, Layout, LayoutError};
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use self::global::Global; pub use self::global::Global;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use self::system::System; pub use self::system::System;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc}; pub use alloc_crate::alloc::{alloc, alloc_zeroed, dealloc, realloc};
#[cfg(all(feature = "alloc", not(no_global_oom_handling)))] #[cfg(all(feature = "alloc", not(no_global_oom_handling)))]
pub use alloc_crate::alloc::handle_alloc_error; pub use alloc_crate::alloc::handle_alloc_error;
/// The `AllocError` error indicates an allocation failure /// The `AllocError` error indicates an allocation failure
/// that may be due to resource exhaustion or to /// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this /// something wrong when combining the given input arguments with this
/// allocator. /// allocator.
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct AllocError; pub struct AllocError;
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for AllocError {} impl std::error::Error for AllocError {}
// (we need this for downstream impl of trait Error) // (we need this for downstream impl of trait Error)
impl fmt::Display for AllocError { impl fmt::Display for AllocError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("memory allocation failed") f.write_str("memory allocation failed")
} }
} }
/// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of /// An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of
/// data described via [`Layout`][]. /// data described via [`Layout`][].
/// ///
/// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having /// `Allocator` is designed to be implemented on ZSTs, references, or smart pointers because having
/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the /// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
/// allocated memory. /// allocated memory.
/// ///
/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying /// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `Allocator`. If an underlying
/// allocator does not support this (like jemalloc) or return a null pointer (such as /// allocator does not support this (like jemalloc) or return a null pointer (such as
/// `libc::malloc`), this must be caught by the implementation. /// `libc::malloc`), this must be caught by the implementation.
/// ///
/// ### Currently allocated memory /// ### Currently allocated memory
/// ///
/// Some of the methods require that a memory block be *currently allocated* via an allocator. This /// Some of the methods require that a memory block be *currently allocated* via an allocator. This
/// means that: /// means that:
/// ///
/// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or /// * the starting address for that memory block was previously returned by [`allocate`], [`grow`], or
/// [`shrink`], and /// [`shrink`], and
/// ///
/// * the memory block has not been subsequently deallocated, where blocks are either deallocated /// * the memory block has not been subsequently deallocated, where blocks are either deallocated
/// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or /// directly by being passed to [`deallocate`] or were changed by being passed to [`grow`] or
/// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer /// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
/// remains valid. /// remains valid.
/// ///
/// [`allocate`]: Allocator::allocate /// [`allocate`]: Allocator::allocate
/// [`grow`]: Allocator::grow /// [`grow`]: Allocator::grow
/// [`shrink`]: Allocator::shrink /// [`shrink`]: Allocator::shrink
/// [`deallocate`]: Allocator::deallocate /// [`deallocate`]: Allocator::deallocate
/// ///
/// ### Memory fitting /// ### Memory fitting
/// ///
/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to /// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the /// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
/// following conditions must hold: /// following conditions must hold:
/// ///
/// * The block must be allocated with the same alignment as [`layout.align()`], and /// * The block must be allocated with the same alignment as [`layout.align()`], and
/// ///
/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where: /// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
/// - `min` is the size of the layout most recently used to allocate the block, and /// - `min` is the size of the layout most recently used to allocate the block, and
/// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`]. /// - `max` is the latest actual size returned from [`allocate`], [`grow`], or [`shrink`].
/// ///
/// [`layout.align()`]: Layout::align /// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size /// [`layout.size()`]: Layout::size
/// ///
/// # Safety /// # Safety
/// ///
/// * Memory blocks returned from an allocator must point to valid memory and retain their validity /// * Memory blocks returned from an allocator must point to valid memory and retain their validity
/// until the instance and all of its clones are dropped, /// until the instance and all of its clones are dropped,
/// ///
/// * cloning or moving the allocator must not invalidate memory blocks returned from this /// * cloning or moving the allocator must not invalidate memory blocks returned from this
/// allocator. A cloned allocator must behave like the same allocator, and /// allocator. A cloned allocator must behave like the same allocator, and
/// ///
/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other /// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
/// method of the allocator. /// method of the allocator.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
pub unsafe trait Allocator { pub unsafe trait Allocator {
/// Attempts to allocate a block of memory. /// Attempts to allocate a block of memory.
/// ///
/// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`.
/// ///
/// The returned block may have a larger size than specified by `layout.size()`, and may or may /// The returned block may have a larger size than specified by `layout.size()`, and may or may
/// not have its contents initialized. /// not have its contents initialized.
/// ///
/// # Errors /// # Errors
/// ///
/// Returning `Err` indicates that either memory is exhausted or `layout` does not meet /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
/// allocator's size or alignment constraints. /// allocator's size or alignment constraints.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>; fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
/// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized. /// Behaves like `allocate`, but also ensures that the returned memory is zero-initialized.
/// ///
/// # Errors /// # Errors
/// ///
/// Returning `Err` indicates that either memory is exhausted or `layout` does not meet /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
/// allocator's size or alignment constraints. /// allocator's size or alignment constraints.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
#[inline(always)] #[inline(always)]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let ptr = self.allocate(layout)?; let ptr = self.allocate(layout)?;
// SAFETY: `alloc` returns a valid memory block // SAFETY: `alloc` returns a valid memory block
unsafe { ptr.cast::<u8>().as_ptr().write_bytes(0, ptr.len()) } unsafe { ptr.cast::<u8>().as_ptr().write_bytes(0, ptr.len()) }
Ok(ptr) Ok(ptr)
} }
/// Deallocates the memory referenced by `ptr`. /// Deallocates the memory referenced by `ptr`.
/// ///
/// # Safety /// # Safety
/// ///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and
/// * `layout` must [*fit*] that block of memory. /// * `layout` must [*fit*] that block of memory.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting /// [*fit*]: #memory-fitting
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout); unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
/// Attempts to extend the memory block. /// Attempts to extend the memory block.
/// ///
/// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
/// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
/// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout.
/// ///
/// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
/// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
/// allocation was grown in-place. The newly returned pointer is the only valid pointer /// allocation was grown in-place. The newly returned pointer is the only valid pointer
/// for accessing this memory now. /// for accessing this memory now.
/// ///
/// If this method returns `Err`, then ownership of the memory block has not been transferred to /// If this method returns `Err`, then ownership of the memory block has not been transferred to
/// this allocator, and the contents of the memory block are unaltered. /// this allocator, and the contents of the memory block are unaltered.
/// ///
/// # Safety /// # Safety
/// ///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
/// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
/// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
/// ///
/// Note that `new_layout.align()` need not be the same as `old_layout.align()`. /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting /// [*fit*]: #memory-fitting
/// ///
/// # Errors /// # Errors
/// ///
/// Returns `Err` if the new layout does not meet the allocator's size and alignment /// Returns `Err` if the new layout does not meet the allocator's size and alignment
/// constraints of the allocator, or if growing otherwise fails. /// constraints of the allocator, or if growing otherwise fails.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
#[inline(always)] #[inline(always)]
unsafe fn grow( unsafe fn grow(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() >= old_layout.size(), new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`" "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
); );
let new_ptr = self.allocate(new_layout)?; let new_ptr = self.allocate(new_layout)?;
// SAFETY: because `new_layout.size()` must be greater than or equal to // SAFETY: because `new_layout.size()` must be greater than or equal to
// `old_layout.size()`, both the old and new memory allocation are valid for reads and // `old_layout.size()`, both the old and new memory allocation are valid for reads and
// writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
// deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
// safe. The safety contract for `dealloc` must be upheld by the caller. // safe. The safety contract for `dealloc` must be upheld by the caller.
unsafe { unsafe {
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size()); ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size());
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
} }
Ok(new_ptr) Ok(new_ptr)
} }
/// Behaves like `grow`, but also ensures that the new contents are set to zero before being /// Behaves like `grow`, but also ensures that the new contents are set to zero before being
/// returned. /// returned.
/// ///
/// The memory block will contain the following contents after a successful call to /// The memory block will contain the following contents after a successful call to
/// `grow_zeroed`: /// `grow_zeroed`:
/// * Bytes `0..old_layout.size()` are preserved from the original allocation. /// * Bytes `0..old_layout.size()` are preserved from the original allocation.
/// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on /// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on
/// the allocator implementation. `old_size` refers to the size of the memory block prior /// the allocator implementation. `old_size` refers to the size of the memory block prior
/// to the `grow_zeroed` call, which may be larger than the size that was originally /// to the `grow_zeroed` call, which may be larger than the size that was originally
/// requested when it was allocated. /// requested when it was allocated.
/// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory
/// block returned by the `grow_zeroed` call. /// block returned by the `grow_zeroed` call.
/// ///
/// # Safety /// # Safety
/// ///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
/// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
/// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`.
/// ///
/// Note that `new_layout.align()` need not be the same as `old_layout.align()`. /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting /// [*fit*]: #memory-fitting
/// ///
/// # Errors /// # Errors
/// ///
/// Returns `Err` if the new layout does not meet the allocator's size and alignment /// Returns `Err` if the new layout does not meet the allocator's size and alignment
/// constraints of the allocator, or if growing otherwise fails. /// constraints of the allocator, or if growing otherwise fails.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
#[inline(always)] #[inline(always)]
unsafe fn grow_zeroed( unsafe fn grow_zeroed(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() >= old_layout.size(), new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`" "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
); );
let new_ptr = self.allocate_zeroed(new_layout)?; let new_ptr = self.allocate_zeroed(new_layout)?;
// SAFETY: because `new_layout.size()` must be greater than or equal to // SAFETY: because `new_layout.size()` must be greater than or equal to
// `old_layout.size()`, both the old and new memory allocation are valid for reads and // `old_layout.size()`, both the old and new memory allocation are valid for reads and
// writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet
// deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
// safe. The safety contract for `dealloc` must be upheld by the caller. // safe. The safety contract for `dealloc` must be upheld by the caller.
unsafe { unsafe {
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size()); ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_layout.size());
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
} }
Ok(new_ptr) Ok(new_ptr)
} }
/// Attempts to shrink the memory block. /// Attempts to shrink the memory block.
/// ///
/// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated
/// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish
/// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout.
/// ///
/// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
/// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the /// transferred to this allocator. Any access to the old `ptr` is Undefined Behavior, even if the
/// allocation was shrunk in-place. The newly returned pointer is the only valid pointer /// allocation was shrunk in-place. The newly returned pointer is the only valid pointer
/// for accessing this memory now. /// for accessing this memory now.
/// ///
/// If this method returns `Err`, then ownership of the memory block has not been transferred to /// If this method returns `Err`, then ownership of the memory block has not been transferred to
/// this allocator, and the contents of the memory block are unaltered. /// this allocator, and the contents of the memory block are unaltered.
/// ///
/// # Safety /// # Safety
/// ///
/// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator.
/// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.).
/// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`.
/// ///
/// Note that `new_layout.align()` need not be the same as `old_layout.align()`. /// Note that `new_layout.align()` need not be the same as `old_layout.align()`.
/// ///
/// [*currently allocated*]: #currently-allocated-memory /// [*currently allocated*]: #currently-allocated-memory
/// [*fit*]: #memory-fitting /// [*fit*]: #memory-fitting
/// ///
/// # Errors /// # Errors
/// ///
/// Returns `Err` if the new layout does not meet the allocator's size and alignment /// Returns `Err` if the new layout does not meet the allocator's size and alignment
/// constraints of the allocator, or if shrinking otherwise fails. /// constraints of the allocator, or if shrinking otherwise fails.
/// ///
/// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
/// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
/// this trait atop an underlying native allocation library that aborts on memory exhaustion.) /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
/// ///
/// Clients wishing to abort computation in response to an allocation error are encouraged to /// Clients wishing to abort computation in response to an allocation error are encouraged to
/// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
/// ///
/// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
#[inline(always)] #[inline(always)]
unsafe fn shrink( unsafe fn shrink(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() <= old_layout.size(), new_layout.size() <= old_layout.size(),
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`" "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
); );
let new_ptr = self.allocate(new_layout)?; let new_ptr = self.allocate(new_layout)?;
// SAFETY: because `new_layout.size()` must be lower than or equal to // SAFETY: because `new_layout.size()` must be lower than or equal to
// `old_layout.size()`, both the old and new memory allocation are valid for reads and // `old_layout.size()`, both the old and new memory allocation are valid for reads and
// writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet
// deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is
// safe. The safety contract for `dealloc` must be upheld by the caller. // safe. The safety contract for `dealloc` must be upheld by the caller.
unsafe { unsafe {
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_layout.size()); ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_layout.size());
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
} }
Ok(new_ptr) Ok(new_ptr)
} }
/// Creates a "by reference" adapter for this instance of `Allocator`. /// Creates a "by reference" adapter for this instance of `Allocator`.
/// ///
/// The returned adapter also implements `Allocator` and will simply borrow this. /// The returned adapter also implements `Allocator` and will simply borrow this.
#[inline(always)] #[inline(always)]
fn by_ref(&self) -> &Self fn by_ref(&self) -> &Self
where where
Self: Sized, Self: Sized,
{ {
self self
} }
} }
unsafe impl<A> Allocator for &A unsafe impl<A> Allocator for &A
where where
A: Allocator + ?Sized, A: Allocator + ?Sized,
{ {
#[inline(always)] #[inline(always)]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate(layout) (**self).allocate(layout)
} }
#[inline(always)] #[inline(always)]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate_zeroed(layout) (**self).allocate_zeroed(layout)
} }
#[inline(always)] #[inline(always)]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
// SAFETY: the safety contract must be upheld by the caller // SAFETY: the safety contract must be upheld by the caller
unsafe { (**self).deallocate(ptr, layout) } unsafe { (**self).deallocate(ptr, layout) }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow( unsafe fn grow(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller // SAFETY: the safety contract must be upheld by the caller
unsafe { (**self).grow(ptr, old_layout, new_layout) } unsafe { (**self).grow(ptr, old_layout, new_layout) }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow_zeroed( unsafe fn grow_zeroed(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller // SAFETY: the safety contract must be upheld by the caller
unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
} }
#[inline(always)] #[inline(always)]
unsafe fn shrink( unsafe fn shrink(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: the safety contract must be upheld by the caller // SAFETY: the safety contract must be upheld by the caller
unsafe { (**self).shrink(ptr, old_layout, new_layout) } unsafe { (**self).shrink(ptr, old_layout, new_layout) }
} }
} }

View File

@ -1,172 +1,172 @@
use core::ptr::NonNull; use core::ptr::NonNull;
pub use std::alloc::System; pub use std::alloc::System;
use crate::stable::{assume, invalid_mut}; use crate::stable::{assume, invalid_mut};
use super::{AllocError, Allocator, GlobalAlloc as _, Layout}; use super::{AllocError, Allocator, GlobalAlloc as _, Layout};
unsafe impl Allocator for System { unsafe impl Allocator for System {
#[inline(always)] #[inline(always)]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
alloc_impl(layout, false) alloc_impl(layout, false)
} }
#[inline(always)] #[inline(always)]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
alloc_impl(layout, true) alloc_impl(layout, true)
} }
#[inline(always)] #[inline(always)]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 { if layout.size() != 0 {
// SAFETY: `layout` is non-zero in size, // SAFETY: `layout` is non-zero in size,
// other conditions must be upheld by the caller // other conditions must be upheld by the caller
unsafe { System.dealloc(ptr.as_ptr(), layout) } unsafe { System.dealloc(ptr.as_ptr(), layout) }
} }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow( unsafe fn grow(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: all conditions must be upheld by the caller // SAFETY: all conditions must be upheld by the caller
unsafe { grow_impl(ptr, old_layout, new_layout, false) } unsafe { grow_impl(ptr, old_layout, new_layout, false) }
} }
#[inline(always)] #[inline(always)]
unsafe fn grow_zeroed( unsafe fn grow_zeroed(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
// SAFETY: all conditions must be upheld by the caller // SAFETY: all conditions must be upheld by the caller
unsafe { grow_impl(ptr, old_layout, new_layout, true) } unsafe { grow_impl(ptr, old_layout, new_layout, true) }
} }
#[inline(always)] #[inline(always)]
unsafe fn shrink( unsafe fn shrink(
&self, &self,
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() <= old_layout.size(), new_layout.size() <= old_layout.size(),
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`" "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
); );
match new_layout.size() { match new_layout.size() {
// SAFETY: conditions must be upheld by the caller // SAFETY: conditions must be upheld by the caller
0 => unsafe { 0 => unsafe {
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
invalid_mut(new_layout.align()), invalid_mut(new_layout.align()),
0, 0,
))) )))
}, },
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
new_size if old_layout.align() == new_layout.align() => unsafe { new_size if old_layout.align() == new_layout.align() => unsafe {
// `realloc` probably checks for `new_size <= old_layout.size()` or something similar. // `realloc` probably checks for `new_size <= old_layout.size()` or something similar.
assume(new_size <= old_layout.size()); assume(new_size <= old_layout.size());
let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size); let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
new_size, new_size,
))) )))
}, },
// SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,
// both the old and new memory allocation are valid for reads and writes for `new_size` // both the old and new memory allocation are valid for reads and writes for `new_size`
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
// for `dealloc` must be upheld by the caller. // for `dealloc` must be upheld by the caller.
new_size => unsafe { new_size => unsafe {
let new_ptr = self.allocate(new_layout)?; let new_ptr = self.allocate(new_layout)?;
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size); core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size);
self.deallocate(ptr, old_layout); self.deallocate(ptr, old_layout);
Ok(new_ptr) Ok(new_ptr)
}, },
} }
} }
} }
#[inline(always)] #[inline(always)]
fn alloc_impl(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> { fn alloc_impl(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() { match layout.size() {
0 => Ok(unsafe { 0 => Ok(unsafe {
NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
invalid_mut(layout.align()), invalid_mut(layout.align()),
0, 0,
)) ))
}), }),
// SAFETY: `layout` is non-zero in size, // SAFETY: `layout` is non-zero in size,
size => unsafe { size => unsafe {
let raw_ptr = if zeroed { let raw_ptr = if zeroed {
System.alloc_zeroed(layout) System.alloc_zeroed(layout)
} else { } else {
System.alloc(layout) System.alloc(layout)
}; };
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
size, size,
))) )))
}, },
} }
} }
// SAFETY: Same as `Allocator::grow` // SAFETY: Same as `Allocator::grow`
#[inline(always)] #[inline(always)]
unsafe fn grow_impl( unsafe fn grow_impl(
ptr: NonNull<u8>, ptr: NonNull<u8>,
old_layout: Layout, old_layout: Layout,
new_layout: Layout, new_layout: Layout,
zeroed: bool, zeroed: bool,
) -> Result<NonNull<[u8]>, AllocError> { ) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!( debug_assert!(
new_layout.size() >= old_layout.size(), new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`" "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
); );
match old_layout.size() { match old_layout.size() {
0 => alloc_impl(new_layout, zeroed), 0 => alloc_impl(new_layout, zeroed),
// SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
// as required by safety conditions. Other conditions must be upheld by the caller // as required by safety conditions. Other conditions must be upheld by the caller
old_size if old_layout.align() == new_layout.align() => unsafe { old_size if old_layout.align() == new_layout.align() => unsafe {
let new_size = new_layout.size(); let new_size = new_layout.size();
// `realloc` probably checks for `new_size >= old_layout.size()` or something similar. // `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
assume(new_size >= old_layout.size()); assume(new_size >= old_layout.size());
let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size); let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size);
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
if zeroed { if zeroed {
raw_ptr.add(old_size).write_bytes(0, new_size - old_size); raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
} }
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
ptr.as_ptr(), ptr.as_ptr(),
new_size, new_size,
))) )))
}, },
// SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,
// both the old and new memory allocation are valid for reads and writes for `old_size` // both the old and new memory allocation are valid for reads and writes for `old_size`
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
// for `dealloc` must be upheld by the caller. // for `dealloc` must be upheld by the caller.
old_size => unsafe { old_size => unsafe {
let new_ptr = alloc_impl(new_layout, zeroed)?; let new_ptr = alloc_impl(new_layout, zeroed)?;
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size); core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size);
System.deallocate(ptr, old_layout); System.deallocate(ptr, old_layout);
Ok(new_ptr) Ok(new_ptr)
}, },
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,83 +1,83 @@
/// Creates a [`Vec`] containing the arguments. /// Creates a [`Vec`] containing the arguments.
/// ///
/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions. /// `vec!` allows `Vec`s to be defined with the same syntax as array expressions.
/// There are two forms of this macro: /// There are two forms of this macro:
/// ///
/// - Create a [`Vec`] containing a given list of elements: /// - Create a [`Vec`] containing a given list of elements:
/// ///
/// ``` /// ```
/// use allocator_api2::vec; /// use allocator_api2::vec;
/// let v = vec![1, 2, 3]; /// let v = vec![1, 2, 3];
/// assert_eq!(v[0], 1); /// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2); /// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3); /// assert_eq!(v[2], 3);
/// ``` /// ```
/// ///
/// ///
/// ``` /// ```
/// use allocator_api2::{vec, alloc::Global}; /// use allocator_api2::{vec, alloc::Global};
/// let v = vec![in Global; 1, 2, 3]; /// let v = vec![in Global; 1, 2, 3];
/// assert_eq!(v[0], 1); /// assert_eq!(v[0], 1);
/// assert_eq!(v[1], 2); /// assert_eq!(v[1], 2);
/// assert_eq!(v[2], 3); /// assert_eq!(v[2], 3);
/// ``` /// ```
/// ///
/// - Create a [`Vec`] from a given element and size: /// - Create a [`Vec`] from a given element and size:
/// ///
/// ``` /// ```
/// use allocator_api2::vec; /// use allocator_api2::vec;
/// let v = vec![1; 3]; /// let v = vec![1; 3];
/// assert_eq!(v, [1, 1, 1]); /// assert_eq!(v, [1, 1, 1]);
/// ``` /// ```
/// ///
/// ``` /// ```
/// use allocator_api2::{vec, alloc::Global}; /// use allocator_api2::{vec, alloc::Global};
/// let v = vec![in Global; 1; 3]; /// let v = vec![in Global; 1; 3];
/// assert_eq!(v, [1, 1, 1]); /// assert_eq!(v, [1, 1, 1]);
/// ``` /// ```
/// ///
/// Note that unlike array expressions this syntax supports all elements /// Note that unlike array expressions this syntax supports all elements
/// which implement [`Clone`] and the number of elements doesn't have to be /// which implement [`Clone`] and the number of elements doesn't have to be
/// a constant. /// a constant.
/// ///
/// This will use `clone` to duplicate an expression, so one should be careful /// This will use `clone` to duplicate an expression, so one should be careful
/// using this with types having a nonstandard `Clone` implementation. For /// using this with types having a nonstandard `Clone` implementation. For
/// example, `vec![Rc::new(1); 5]` will create a vector of five references /// example, `vec![Rc::new(1); 5]` will create a vector of five references
/// to the same boxed integer value, not five references pointing to independently /// to the same boxed integer value, not five references pointing to independently
/// boxed integers. /// boxed integers.
/// ///
/// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector. /// Also, note that `vec![expr; 0]` is allowed, and produces an empty vector.
/// This will still evaluate `expr`, however, and immediately drop the resulting value, so /// This will still evaluate `expr`, however, and immediately drop the resulting value, so
/// be mindful of side effects. /// be mindful of side effects.
/// ///
/// [`Vec`]: crate::vec::Vec /// [`Vec`]: crate::vec::Vec
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[macro_export] #[macro_export]
macro_rules! vec { macro_rules! vec {
(in $alloc:expr $(;)?) => ( (in $alloc:expr $(;)?) => (
$crate::vec::Vec::new() $crate::vec::Vec::new_in($alloc)
); );
(in $alloc:expr; $elem:expr; $n:expr) => ( (in $alloc:expr; $elem:expr; $n:expr) => (
$crate::vec::from_elem_in($elem, $n, $alloc) $crate::vec::from_elem_in($elem, $n, $alloc)
); );
(in $alloc:expr; $($x:expr),+ $(,)?) => ( (in $alloc:expr; $($x:expr),+ $(,)?) => (
$crate::boxed::Box::<[_]>::into_vec( $crate::boxed::Box::<[_]>::into_vec(
$crate::boxed::Box::slice( $crate::boxed::Box::slice(
$crate::boxed::Box::new_in([$($x),+], $alloc) $crate::boxed::Box::new_in([$($x),+], $alloc)
) )
) )
); );
() => ( () => (
$crate::vec::Vec::new() $crate::vec::Vec::new()
); );
($elem:expr; $n:expr) => ( ($elem:expr; $n:expr) => (
$crate::vec::from_elem($elem, $n) $crate::vec::from_elem($elem, $n)
); );
($($x:expr),+ $(,)?) => ( ($($x:expr),+ $(,)?) => (
$crate::boxed::Box::<[_]>::into_vec( $crate::boxed::Box::<[_]>::into_vec(
$crate::boxed::Box::slice( $crate::boxed::Box::slice(
$crate::boxed::Box::new([$($x),+]) $crate::boxed::Box::new([$($x),+])
) )
) )
); );
} }

View File

@ -1,62 +1,62 @@
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
#![allow(clippy::needless_doctest_main, clippy::partialeq_ne_impl)] #![allow(clippy::needless_doctest_main, clippy::partialeq_ne_impl)]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub use self::slice::SliceExt; pub use self::slice::SliceExt;
pub mod alloc; pub mod alloc;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod boxed; pub mod boxed;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod raw_vec; mod raw_vec;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod vec; pub mod vec;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod macros; mod macros;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
mod slice; mod slice;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[track_caller] #[track_caller]
#[inline(always)] #[inline(always)]
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
unsafe fn assume(v: bool) { unsafe fn assume(v: bool) {
if !v { if !v {
core::unreachable!() core::unreachable!()
} }
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[track_caller] #[track_caller]
#[inline(always)] #[inline(always)]
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
unsafe fn assume(v: bool) { unsafe fn assume(v: bool) {
if !v { if !v {
unsafe { unsafe {
core::hint::unreachable_unchecked(); core::hint::unreachable_unchecked();
} }
} }
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[inline(always)] #[inline(always)]
fn addr<T>(x: *const T) -> usize { fn addr<T>(x: *const T) -> usize {
#[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)] #[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)]
unsafe { unsafe {
core::mem::transmute(x) core::mem::transmute(x)
} }
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[inline(always)] #[inline(always)]
fn invalid_mut<T>(addr: usize) -> *mut T { fn invalid_mut<T>(addr: usize) -> *mut T {
#[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)] #[allow(clippy::useless_transmute, clippy::transmutes_expressible_as_ptr_casts)]
unsafe { unsafe {
core::mem::transmute(addr) core::mem::transmute(addr)
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,171 +1,171 @@
use crate::{ use crate::{
alloc::{Allocator, Global}, alloc::{Allocator, Global},
vec::Vec, vec::Vec,
}; };
/// Slice methods that use `Box` and `Vec` from this crate. /// Slice methods that use `Box` and `Vec` from this crate.
pub trait SliceExt<T> { pub trait SliceExt<T> {
/// Copies `self` into a new `Vec`. /// Copies `self` into a new `Vec`.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// let s = [10, 40, 30]; /// let s = [10, 40, 30];
/// let x = s.to_vec(); /// let x = s.to_vec();
/// // Here, `s` and `x` can be modified independently. /// // Here, `s` and `x` can be modified independently.
/// ``` /// ```
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[inline(always)] #[inline(always)]
fn to_vec(&self) -> Vec<T, Global> fn to_vec(&self) -> Vec<T, Global>
where where
T: Clone, T: Clone,
{ {
self.to_vec_in(Global) self.to_vec_in(Global)
} }
/// Copies `self` into a new `Vec` with an allocator. /// Copies `self` into a new `Vec` with an allocator.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(allocator_api)] /// #![feature(allocator_api)]
/// ///
/// use std::alloc::System; /// use std::alloc::System;
/// ///
/// let s = [10, 40, 30]; /// let s = [10, 40, 30];
/// let x = s.to_vec_in(System); /// let x = s.to_vec_in(System);
/// // Here, `s` and `x` can be modified independently. /// // Here, `s` and `x` can be modified independently.
/// ``` /// ```
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A> fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
where where
T: Clone; T: Clone;
/// Creates a vector by copying a slice `n` times. /// Creates a vector by copying a slice `n` times.
/// ///
/// # Panics /// # Panics
/// ///
/// This function will panic if the capacity would overflow. /// This function will panic if the capacity would overflow.
/// ///
/// # Examples /// # Examples
/// ///
/// Basic usage: /// Basic usage:
/// ///
/// ``` /// ```
/// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
/// ``` /// ```
/// ///
/// A panic upon overflow: /// A panic upon overflow:
/// ///
/// ```should_panic /// ```should_panic
/// // this will panic at runtime /// // this will panic at runtime
/// b"0123456789abcdef".repeat(usize::MAX); /// b"0123456789abcdef".repeat(usize::MAX);
/// ``` /// ```
fn repeat(&self, n: usize) -> Vec<T, Global> fn repeat(&self, n: usize) -> Vec<T, Global>
where where
T: Copy; T: Copy;
} }
impl<T> SliceExt<T> for [T] { impl<T> SliceExt<T> for [T] {
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[inline] #[inline]
fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A> fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
where where
T: Clone, T: Clone,
{ {
struct DropGuard<'a, T, A: Allocator> { struct DropGuard<'a, T, A: Allocator> {
vec: &'a mut Vec<T, A>, vec: &'a mut Vec<T, A>,
num_init: usize, num_init: usize,
} }
impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
// SAFETY: // SAFETY:
// items were marked initialized in the loop below // items were marked initialized in the loop below
unsafe { unsafe {
self.vec.set_len(self.num_init); self.vec.set_len(self.num_init);
} }
} }
} }
let mut vec = Vec::with_capacity_in(self.len(), alloc); let mut vec = Vec::with_capacity_in(self.len(), alloc);
let mut guard = DropGuard { let mut guard = DropGuard {
vec: &mut vec, vec: &mut vec,
num_init: 0, num_init: 0,
}; };
let slots = guard.vec.spare_capacity_mut(); let slots = guard.vec.spare_capacity_mut();
// .take(slots.len()) is necessary for LLVM to remove bounds checks // .take(slots.len()) is necessary for LLVM to remove bounds checks
// and has better codegen than zip. // and has better codegen than zip.
for (i, b) in self.iter().enumerate().take(slots.len()) { for (i, b) in self.iter().enumerate().take(slots.len()) {
guard.num_init = i; guard.num_init = i;
slots[i].write(b.clone()); slots[i].write(b.clone());
} }
core::mem::forget(guard); core::mem::forget(guard);
// SAFETY: // SAFETY:
// the vec was allocated and initialized above to at least this length. // the vec was allocated and initialized above to at least this length.
unsafe { unsafe {
vec.set_len(self.len()); vec.set_len(self.len());
} }
vec vec
} }
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[inline] #[inline]
fn repeat(&self, n: usize) -> Vec<T, Global> fn repeat(&self, n: usize) -> Vec<T, Global>
where where
T: Copy, T: Copy,
{ {
if n == 0 { if n == 0 {
return Vec::new(); return Vec::new();
} }
// If `n` is larger than zero, it can be split as // If `n` is larger than zero, it can be split as
// `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`. // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`.
// `2^expn` is the number represented by the leftmost '1' bit of `n`, // `2^expn` is the number represented by the leftmost '1' bit of `n`,
// and `rem` is the remaining part of `n`. // and `rem` is the remaining part of `n`.
// Using `Vec` to access `set_len()`. // Using `Vec` to access `set_len()`.
let capacity = self.len().checked_mul(n).expect("capacity overflow"); let capacity = self.len().checked_mul(n).expect("capacity overflow");
let mut buf = Vec::with_capacity(capacity); let mut buf = Vec::with_capacity(capacity);
// `2^expn` repetition is done by doubling `buf` `expn`-times. // `2^expn` repetition is done by doubling `buf` `expn`-times.
buf.extend(self); buf.extend(self);
{ {
let mut m = n >> 1; let mut m = n >> 1;
// If `m > 0`, there are remaining bits up to the leftmost '1'. // If `m > 0`, there are remaining bits up to the leftmost '1'.
while m > 0 { while m > 0 {
// `buf.extend(buf)`: // `buf.extend(buf)`:
unsafe { unsafe {
core::ptr::copy_nonoverlapping( core::ptr::copy_nonoverlapping(
buf.as_ptr(), buf.as_ptr(),
(buf.as_mut_ptr() as *mut T).add(buf.len()), (buf.as_mut_ptr() as *mut T).add(buf.len()),
buf.len(), buf.len(),
); );
// `buf` has capacity of `self.len() * n`. // `buf` has capacity of `self.len() * n`.
let buf_len = buf.len(); let buf_len = buf.len();
buf.set_len(buf_len * 2); buf.set_len(buf_len * 2);
} }
m >>= 1; m >>= 1;
} }
} }
// `rem` (`= n - 2^expn`) repetition is done by copying // `rem` (`= n - 2^expn`) repetition is done by copying
// first `rem` repetitions from `buf` itself. // first `rem` repetitions from `buf` itself.
let rem_len = capacity - buf.len(); // `self.len() * rem` let rem_len = capacity - buf.len(); // `self.len() * rem`
if rem_len > 0 { if rem_len > 0 {
// `buf.extend(buf[0 .. rem_len])`: // `buf.extend(buf[0 .. rem_len])`:
unsafe { unsafe {
// This is non-overlapping since `2^expn > rem`. // This is non-overlapping since `2^expn > rem`.
core::ptr::copy_nonoverlapping( core::ptr::copy_nonoverlapping(
buf.as_ptr(), buf.as_ptr(),
(buf.as_mut_ptr() as *mut T).add(buf.len()), (buf.as_mut_ptr() as *mut T).add(buf.len()),
rem_len, rem_len,
); );
// `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`). // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`).
buf.set_len(capacity); buf.set_len(capacity);
} }
} }
buf buf
} }
} }

View File

@ -1,242 +1,242 @@
use core::fmt; use core::fmt;
use core::iter::FusedIterator; use core::iter::FusedIterator;
use core::mem::{self, size_of, ManuallyDrop}; use core::mem::{self, size_of, ManuallyDrop};
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::slice::{self}; use core::slice::{self};
use crate::stable::alloc::{Allocator, Global}; use crate::stable::alloc::{Allocator, Global};
use super::Vec; use super::Vec;
/// A draining iterator for `Vec<T>`. /// A draining iterator for `Vec<T>`.
/// ///
/// This `struct` is created by [`Vec::drain`]. /// This `struct` is created by [`Vec::drain`].
/// See its documentation for more. /// See its documentation for more.
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```
/// let mut v = vec![0, 1, 2]; /// let mut v = vec![0, 1, 2];
/// let iter: std::vec::Drain<_> = v.drain(..); /// let iter: std::vec::Drain<_> = v.drain(..);
/// ``` /// ```
pub struct Drain<'a, T: 'a, A: Allocator + 'a = Global> { pub struct Drain<'a, T: 'a, A: Allocator + 'a = Global> {
/// Index of tail to preserve /// Index of tail to preserve
pub(super) tail_start: usize, pub(super) tail_start: usize,
/// Length of tail /// Length of tail
pub(super) tail_len: usize, pub(super) tail_len: usize,
/// Current remaining range to remove /// Current remaining range to remove
pub(super) iter: slice::Iter<'a, T>, pub(super) iter: slice::Iter<'a, T>,
pub(super) vec: NonNull<Vec<T, A>>, pub(super) vec: NonNull<Vec<T, A>>,
} }
impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> { impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Drain").field(&self.iter.as_slice()).finish() f.debug_tuple("Drain").field(&self.iter.as_slice()).finish()
} }
} }
impl<'a, T, A: Allocator> Drain<'a, T, A> { impl<'a, T, A: Allocator> Drain<'a, T, A> {
/// Returns the remaining items of this iterator as a slice. /// Returns the remaining items of this iterator as a slice.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// let mut vec = vec!['a', 'b', 'c']; /// let mut vec = vec!['a', 'b', 'c'];
/// let mut drain = vec.drain(..); /// let mut drain = vec.drain(..);
/// assert_eq!(drain.as_slice(), &['a', 'b', 'c']); /// assert_eq!(drain.as_slice(), &['a', 'b', 'c']);
/// let _ = drain.next().unwrap(); /// let _ = drain.next().unwrap();
/// assert_eq!(drain.as_slice(), &['b', 'c']); /// assert_eq!(drain.as_slice(), &['b', 'c']);
/// ``` /// ```
#[must_use] #[must_use]
#[inline(always)] #[inline(always)]
pub fn as_slice(&self) -> &[T] { pub fn as_slice(&self) -> &[T] {
self.iter.as_slice() self.iter.as_slice()
} }
/// Returns a reference to the underlying allocator. /// Returns a reference to the underlying allocator.
#[must_use] #[must_use]
#[inline(always)] #[inline(always)]
pub fn allocator(&self) -> &A { pub fn allocator(&self) -> &A {
unsafe { self.vec.as_ref().allocator() } unsafe { self.vec.as_ref().allocator() }
} }
/// Keep unyielded elements in the source `Vec`. /// Keep unyielded elements in the source `Vec`.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(drain_keep_rest)] /// #![feature(drain_keep_rest)]
/// ///
/// let mut vec = vec!['a', 'b', 'c']; /// let mut vec = vec!['a', 'b', 'c'];
/// let mut drain = vec.drain(..); /// let mut drain = vec.drain(..);
/// ///
/// assert_eq!(drain.next().unwrap(), 'a'); /// assert_eq!(drain.next().unwrap(), 'a');
/// ///
/// // This call keeps 'b' and 'c' in the vec. /// // This call keeps 'b' and 'c' in the vec.
/// drain.keep_rest(); /// drain.keep_rest();
/// ///
/// // If we wouldn't call `keep_rest()`, /// // If we wouldn't call `keep_rest()`,
/// // `vec` would be empty. /// // `vec` would be empty.
/// assert_eq!(vec, ['b', 'c']); /// assert_eq!(vec, ['b', 'c']);
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn keep_rest(self) { pub fn keep_rest(self) {
// At this moment layout looks like this: // At this moment layout looks like this:
// //
// [head] [yielded by next] [unyielded] [yielded by next_back] [tail] // [head] [yielded by next] [unyielded] [yielded by next_back] [tail]
// ^-- start \_________/-- unyielded_len \____/-- self.tail_len // ^-- start \_________/-- unyielded_len \____/-- self.tail_len
// ^-- unyielded_ptr ^-- tail // ^-- unyielded_ptr ^-- tail
// //
// Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`. // Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`.
// Here we want to // Here we want to
// 1. Move [unyielded] to `start` // 1. Move [unyielded] to `start`
// 2. Move [tail] to a new start at `start + len(unyielded)` // 2. Move [tail] to a new start at `start + len(unyielded)`
// 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)` // 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)`
// a. In case of ZST, this is the only thing we want to do // a. In case of ZST, this is the only thing we want to do
// 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do // 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
let mut this = ManuallyDrop::new(self); let mut this = ManuallyDrop::new(self);
unsafe { unsafe {
let source_vec = this.vec.as_mut(); let source_vec = this.vec.as_mut();
let start = source_vec.len(); let start = source_vec.len();
let tail = this.tail_start; let tail = this.tail_start;
let unyielded_len = this.iter.len(); let unyielded_len = this.iter.len();
let unyielded_ptr = this.iter.as_slice().as_ptr(); let unyielded_ptr = this.iter.as_slice().as_ptr();
// ZSTs have no identity, so we don't need to move them around. // ZSTs have no identity, so we don't need to move them around.
let needs_move = mem::size_of::<T>() != 0; let needs_move = mem::size_of::<T>() != 0;
if needs_move { if needs_move {
let start_ptr = source_vec.as_mut_ptr().add(start); let start_ptr = source_vec.as_mut_ptr().add(start);
// memmove back unyielded elements // memmove back unyielded elements
if unyielded_ptr != start_ptr { if unyielded_ptr != start_ptr {
let src = unyielded_ptr; let src = unyielded_ptr;
let dst = start_ptr; let dst = start_ptr;
ptr::copy(src, dst, unyielded_len); ptr::copy(src, dst, unyielded_len);
} }
// memmove back untouched tail // memmove back untouched tail
if tail != (start + unyielded_len) { if tail != (start + unyielded_len) {
let src = source_vec.as_ptr().add(tail); let src = source_vec.as_ptr().add(tail);
let dst = start_ptr.add(unyielded_len); let dst = start_ptr.add(unyielded_len);
ptr::copy(src, dst, this.tail_len); ptr::copy(src, dst, this.tail_len);
} }
} }
source_vec.set_len(start + unyielded_len + this.tail_len); source_vec.set_len(start + unyielded_len + this.tail_len);
} }
} }
} }
impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> { impl<'a, T, A: Allocator> AsRef<[T]> for Drain<'a, T, A> {
#[inline(always)] #[inline(always)]
fn as_ref(&self) -> &[T] { fn as_ref(&self) -> &[T] {
self.as_slice() self.as_slice()
} }
} }
unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {} unsafe impl<T: Sync, A: Sync + Allocator> Sync for Drain<'_, T, A> {}
unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {} unsafe impl<T: Send, A: Send + Allocator> Send for Drain<'_, T, A> {}
impl<T, A: Allocator> Iterator for Drain<'_, T, A> { impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
type Item = T; type Item = T;
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<T> { fn next(&mut self) -> Option<T> {
self.iter self.iter
.next() .next()
.map(|elt| unsafe { ptr::read(elt as *const _) }) .map(|elt| unsafe { ptr::read(elt as *const _) })
} }
#[inline(always)] #[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint() self.iter.size_hint()
} }
} }
impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> { impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
#[inline(always)] #[inline(always)]
fn next_back(&mut self) -> Option<T> { fn next_back(&mut self) -> Option<T> {
self.iter self.iter
.next_back() .next_back()
.map(|elt| unsafe { ptr::read(elt as *const _) }) .map(|elt| unsafe { ptr::read(elt as *const _) })
} }
} }
impl<T, A: Allocator> Drop for Drain<'_, T, A> { impl<T, A: Allocator> Drop for Drain<'_, T, A> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
/// Moves back the un-`Drain`ed elements to restore the original `Vec`. /// Moves back the un-`Drain`ed elements to restore the original `Vec`.
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>); struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> { impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
fn drop(&mut self) { fn drop(&mut self) {
if self.0.tail_len > 0 { if self.0.tail_len > 0 {
unsafe { unsafe {
let source_vec = self.0.vec.as_mut(); let source_vec = self.0.vec.as_mut();
// memmove back untouched tail, update to new length // memmove back untouched tail, update to new length
let start = source_vec.len(); let start = source_vec.len();
let tail = self.0.tail_start; let tail = self.0.tail_start;
if tail != start { if tail != start {
let src = source_vec.as_ptr().add(tail); let src = source_vec.as_ptr().add(tail);
let dst = source_vec.as_mut_ptr().add(start); let dst = source_vec.as_mut_ptr().add(start);
ptr::copy(src, dst, self.0.tail_len); ptr::copy(src, dst, self.0.tail_len);
} }
source_vec.set_len(start + self.0.tail_len); source_vec.set_len(start + self.0.tail_len);
} }
} }
} }
} }
let iter = mem::replace(&mut self.iter, [].iter()); let iter = mem::replace(&mut self.iter, [].iter());
let drop_len = iter.len(); let drop_len = iter.len();
let mut vec = self.vec; let mut vec = self.vec;
if size_of::<T>() == 0 { if size_of::<T>() == 0 {
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount. // ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`. // this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
unsafe { unsafe {
let vec = vec.as_mut(); let vec = vec.as_mut();
let old_len = vec.len(); let old_len = vec.len();
vec.set_len(old_len + drop_len + self.tail_len); vec.set_len(old_len + drop_len + self.tail_len);
vec.truncate(old_len + self.tail_len); vec.truncate(old_len + self.tail_len);
} }
return; return;
} }
// ensure elements are moved back into their appropriate places, even when drop_in_place panics // ensure elements are moved back into their appropriate places, even when drop_in_place panics
let _guard = DropGuard(self); let _guard = DropGuard(self);
if drop_len == 0 { if drop_len == 0 {
return; return;
} }
// as_slice() must only be called when iter.len() is > 0 because // as_slice() must only be called when iter.len() is > 0 because
// vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate // vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate
// the iterator's internal pointers. Creating a reference to deallocated memory // the iterator's internal pointers. Creating a reference to deallocated memory
// is invalid even when it is zero-length // is invalid even when it is zero-length
let drop_ptr = iter.as_slice().as_ptr(); let drop_ptr = iter.as_slice().as_ptr();
unsafe { unsafe {
// drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place // drop_ptr comes from a slice::Iter which only gives us a &[T] but for drop_in_place
// a pointer with mutable provenance is necessary. Therefore we must reconstruct // a pointer with mutable provenance is necessary. Therefore we must reconstruct
// it from the original vec but also avoid creating a &mut to the front since that could // it from the original vec but also avoid creating a &mut to the front since that could
// invalidate raw pointers to it which some unsafe code might rely on. // invalidate raw pointers to it which some unsafe code might rely on.
let vec_ptr = vec.as_mut().as_mut_ptr(); let vec_ptr = vec.as_mut().as_mut_ptr();
let drop_offset = drop_ptr.offset_from(vec_ptr) as usize; let drop_offset = drop_ptr.offset_from(vec_ptr) as usize;
let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len); let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len);
ptr::drop_in_place(to_drop); ptr::drop_in_place(to_drop);
} }
} }
} }
impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {} impl<T, A: Allocator> ExactSizeIterator for Drain<'_, T, A> {}
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {} impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}

View File

@ -1,198 +1,198 @@
use core::fmt; use core::fmt;
use core::iter::FusedIterator; use core::iter::FusedIterator;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::{self, size_of, ManuallyDrop}; use core::mem::{self, size_of, ManuallyDrop};
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::slice::{self}; use core::slice::{self};
use crate::stable::addr; use crate::stable::addr;
use super::{Allocator, Global, RawVec}; use super::{Allocator, Global, RawVec};
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use super::Vec; use super::Vec;
/// An iterator that moves out of a vector. /// An iterator that moves out of a vector.
/// ///
/// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec) /// This `struct` is created by the `into_iter` method on [`Vec`](super::Vec)
/// (provided by the [`IntoIterator`] trait). /// (provided by the [`IntoIterator`] trait).
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```
/// let v = vec![0, 1, 2]; /// let v = vec![0, 1, 2];
/// let iter: std::vec::IntoIter<_> = v.into_iter(); /// let iter: std::vec::IntoIter<_> = v.into_iter();
/// ``` /// ```
pub struct IntoIter<T, A: Allocator = Global> { pub struct IntoIter<T, A: Allocator = Global> {
pub(super) buf: NonNull<T>, pub(super) buf: NonNull<T>,
pub(super) phantom: PhantomData<T>, pub(super) phantom: PhantomData<T>,
pub(super) cap: usize, pub(super) cap: usize,
// the drop impl reconstructs a RawVec from buf, cap and alloc // the drop impl reconstructs a RawVec from buf, cap and alloc
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop // to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
pub(super) alloc: ManuallyDrop<A>, pub(super) alloc: ManuallyDrop<A>,
pub(super) ptr: *const T, pub(super) ptr: *const T,
pub(super) end: *const T, pub(super) end: *const T,
} }
impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> { impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("IntoIter").field(&self.as_slice()).finish() f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
} }
} }
impl<T, A: Allocator> IntoIter<T, A> { impl<T, A: Allocator> IntoIter<T, A> {
/// Returns the remaining items of this iterator as a slice. /// Returns the remaining items of this iterator as a slice.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// let vec = vec!['a', 'b', 'c']; /// let vec = vec!['a', 'b', 'c'];
/// let mut into_iter = vec.into_iter(); /// let mut into_iter = vec.into_iter();
/// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
/// let _ = into_iter.next().unwrap(); /// let _ = into_iter.next().unwrap();
/// assert_eq!(into_iter.as_slice(), &['b', 'c']); /// assert_eq!(into_iter.as_slice(), &['b', 'c']);
/// ``` /// ```
pub fn as_slice(&self) -> &[T] { pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.ptr, self.len()) } unsafe { slice::from_raw_parts(self.ptr, self.len()) }
} }
/// Returns the remaining items of this iterator as a mutable slice. /// Returns the remaining items of this iterator as a mutable slice.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// let vec = vec!['a', 'b', 'c']; /// let vec = vec!['a', 'b', 'c'];
/// let mut into_iter = vec.into_iter(); /// let mut into_iter = vec.into_iter();
/// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); /// assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
/// into_iter.as_mut_slice()[2] = 'z'; /// into_iter.as_mut_slice()[2] = 'z';
/// assert_eq!(into_iter.next().unwrap(), 'a'); /// assert_eq!(into_iter.next().unwrap(), 'a');
/// assert_eq!(into_iter.next().unwrap(), 'b'); /// assert_eq!(into_iter.next().unwrap(), 'b');
/// assert_eq!(into_iter.next().unwrap(), 'z'); /// assert_eq!(into_iter.next().unwrap(), 'z');
/// ``` /// ```
pub fn as_mut_slice(&mut self) -> &mut [T] { pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { &mut *self.as_raw_mut_slice() } unsafe { &mut *self.as_raw_mut_slice() }
} }
/// Returns a reference to the underlying allocator. /// Returns a reference to the underlying allocator.
#[inline(always)] #[inline(always)]
pub fn allocator(&self) -> &A { pub fn allocator(&self) -> &A {
&self.alloc &self.alloc
} }
fn as_raw_mut_slice(&mut self) -> *mut [T] { fn as_raw_mut_slice(&mut self) -> *mut [T] {
ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len())
} }
} }
impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> { impl<T, A: Allocator> AsRef<[T]> for IntoIter<T, A> {
fn as_ref(&self) -> &[T] { fn as_ref(&self) -> &[T] {
self.as_slice() self.as_slice()
} }
} }
unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {} unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
unsafe impl<T: Sync, A: Allocator + Sync> Sync for IntoIter<T, A> {} unsafe impl<T: Sync, A: Allocator + Sync> Sync for IntoIter<T, A> {}
impl<T, A: Allocator> Iterator for IntoIter<T, A> { impl<T, A: Allocator> Iterator for IntoIter<T, A> {
type Item = T; type Item = T;
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<T> { fn next(&mut self) -> Option<T> {
if self.ptr == self.end { if self.ptr == self.end {
None None
} else if size_of::<T>() == 0 { } else if size_of::<T>() == 0 {
// purposefully don't use 'ptr.offset' because for // purposefully don't use 'ptr.offset' because for
// vectors with 0-size elements this would return the // vectors with 0-size elements this would return the
// same pointer. // same pointer.
self.ptr = self.ptr.cast::<u8>().wrapping_add(1).cast(); self.ptr = self.ptr.cast::<u8>().wrapping_add(1).cast();
// Make up a value of this ZST. // Make up a value of this ZST.
Some(unsafe { mem::zeroed() }) Some(unsafe { mem::zeroed() })
} else { } else {
let old = self.ptr; let old = self.ptr;
self.ptr = unsafe { self.ptr.add(1) }; self.ptr = unsafe { self.ptr.add(1) };
Some(unsafe { ptr::read(old) }) Some(unsafe { ptr::read(old) })
} }
} }
#[inline(always)] #[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
let exact = if size_of::<T>() == 0 { let exact = if size_of::<T>() == 0 {
addr(self.end).wrapping_sub(addr(self.ptr)) addr(self.end).wrapping_sub(addr(self.ptr))
} else { } else {
unsafe { self.end.offset_from(self.ptr) as usize } unsafe { self.end.offset_from(self.ptr) as usize }
}; };
(exact, Some(exact)) (exact, Some(exact))
} }
#[inline(always)] #[inline(always)]
fn count(self) -> usize { fn count(self) -> usize {
self.len() self.len()
} }
} }
impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> { impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
#[inline(always)] #[inline(always)]
fn next_back(&mut self) -> Option<T> { fn next_back(&mut self) -> Option<T> {
if self.end == self.ptr { if self.end == self.ptr {
None None
} else if size_of::<T>() == 0 { } else if size_of::<T>() == 0 {
// See above for why 'ptr.offset' isn't used // See above for why 'ptr.offset' isn't used
self.end = self.end.cast::<u8>().wrapping_add(1).cast(); self.end = self.end.cast::<u8>().wrapping_add(1).cast();
// Make up a value of this ZST. // Make up a value of this ZST.
Some(unsafe { mem::zeroed() }) Some(unsafe { mem::zeroed() })
} else { } else {
self.end = unsafe { self.end.sub(1) }; self.end = unsafe { self.end.sub(1) };
Some(unsafe { ptr::read(self.end) }) Some(unsafe { ptr::read(self.end) })
} }
} }
} }
impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {} impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {}
impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
#[doc(hidden)] #[doc(hidden)]
pub trait NonDrop {} pub trait NonDrop {}
// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr
// and thus we can't implement drop-handling // and thus we can't implement drop-handling
impl<T: Copy> NonDrop for T {} impl<T: Copy> NonDrop for T {}
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> { impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
let mut vec = Vec::<T, A>::with_capacity_in(self.len(), (*self.alloc).clone()); let mut vec = Vec::<T, A>::with_capacity_in(self.len(), (*self.alloc).clone());
vec.extend(self.as_slice().iter().cloned()); vec.extend(self.as_slice().iter().cloned());
vec.into_iter() vec.into_iter()
} }
} }
impl<T, A: Allocator> Drop for IntoIter<T, A> { impl<T, A: Allocator> Drop for IntoIter<T, A> {
fn drop(&mut self) { fn drop(&mut self) {
struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>); struct DropGuard<'a, T, A: Allocator>(&'a mut IntoIter<T, A>);
impl<T, A: Allocator> Drop for DropGuard<'_, T, A> { impl<T, A: Allocator> Drop for DropGuard<'_, T, A> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
// `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec // `IntoIter::alloc` is not used anymore after this and will be dropped by RawVec
let alloc = ManuallyDrop::take(&mut self.0.alloc); let alloc = ManuallyDrop::take(&mut self.0.alloc);
// RawVec handles deallocation // RawVec handles deallocation
let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc); let _ = RawVec::from_raw_parts_in(self.0.buf.as_ptr(), self.0.cap, alloc);
} }
} }
} }
let guard = DropGuard(self); let guard = DropGuard(self);
// destroy the remaining elements // destroy the remaining elements
unsafe { unsafe {
ptr::drop_in_place(guard.0.as_raw_mut_slice()); ptr::drop_in_place(guard.0.as_raw_mut_slice());
} }
// now `guard` will be dropped and do the rest // now `guard` will be dropped and do the rest
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +1,43 @@
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
use alloc_crate::borrow::Cow; use alloc_crate::borrow::Cow;
use crate::stable::alloc::Allocator; use crate::stable::alloc::Allocator;
use super::Vec; use super::Vec;
macro_rules! __impl_slice_eq1 { macro_rules! __impl_slice_eq1 {
([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => { ([$($vars:tt)*] $lhs:ty, $rhs:ty $(where $ty:ty: $bound:ident)?) => {
impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
where where
T: PartialEq<U>, T: PartialEq<U>,
$($ty: $bound)? $($ty: $bound)?
{ {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
#[inline(always)] #[inline(always)]
fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] } fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
} }
} }
} }
__impl_slice_eq1! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> } __impl_slice_eq1! { [A1: Allocator, A2: Allocator] Vec<T, A1>, Vec<U, A2> }
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U] } __impl_slice_eq1! { [A: Allocator] Vec<T, A>, &[U] }
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U] } __impl_slice_eq1! { [A: Allocator] Vec<T, A>, &mut [U] }
__impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A> } __impl_slice_eq1! { [A: Allocator] &[T], Vec<U, A> }
__impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A> } __impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A> }
__impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U] } __impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U] }
__impl_slice_eq1! { [A: Allocator] [T], Vec<U, A> } __impl_slice_eq1! { [A: Allocator] [T], Vec<U, A> }
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
__impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone } __impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone }
__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] } __impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N] }
__impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] } __impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N] }
// NOTE: some less important impls are omitted to reduce code bloat // NOTE: some less important impls are omitted to reduce code bloat
// FIXME(Centril): Reconsider this? // FIXME(Centril): Reconsider this?
//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], } //__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], }
//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, } //__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, }
//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, } //__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, }
//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, } //__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], } //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], } //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], }
//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], } //__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], }

View File

@ -1,31 +1,31 @@
// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. // Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
// //
// The idea is: The length field in SetLenOnDrop is a local variable // The idea is: The length field in SetLenOnDrop is a local variable
// that the optimizer will see does not alias with any stores through the Vec's data // that the optimizer will see does not alias with any stores through the Vec's data
// pointer. This is a workaround for alias analysis issue #32155 // pointer. This is a workaround for alias analysis issue #32155
pub(super) struct SetLenOnDrop<'a> { pub(super) struct SetLenOnDrop<'a> {
len: &'a mut usize, len: &'a mut usize,
local_len: usize, local_len: usize,
} }
impl<'a> SetLenOnDrop<'a> { impl<'a> SetLenOnDrop<'a> {
#[inline(always)] #[inline(always)]
pub(super) fn new(len: &'a mut usize) -> Self { pub(super) fn new(len: &'a mut usize) -> Self {
SetLenOnDrop { SetLenOnDrop {
local_len: *len, local_len: *len,
len, len,
} }
} }
#[inline(always)] #[inline(always)]
pub(super) fn increment_len(&mut self, increment: usize) { pub(super) fn increment_len(&mut self, increment: usize) {
self.local_len += increment; self.local_len += increment;
} }
} }
impl Drop for SetLenOnDrop<'_> { impl Drop for SetLenOnDrop<'_> {
#[inline(always)] #[inline(always)]
fn drop(&mut self) { fn drop(&mut self) {
*self.len = self.local_len; *self.len = self.local_len;
} }
} }

View File

@ -1,135 +1,135 @@
use core::ptr::{self}; use core::ptr::{self};
use core::slice::{self}; use core::slice::{self};
use crate::stable::alloc::{Allocator, Global}; use crate::stable::alloc::{Allocator, Global};
use super::{Drain, Vec}; use super::{Drain, Vec};
/// A splicing iterator for `Vec`. /// A splicing iterator for `Vec`.
/// ///
/// This struct is created by [`Vec::splice()`]. /// This struct is created by [`Vec::splice()`].
/// See its documentation for more. /// See its documentation for more.
/// ///
/// # Example /// # Example
/// ///
/// ``` /// ```
/// let mut v = vec![0, 1, 2]; /// let mut v = vec![0, 1, 2];
/// let new = [7, 8]; /// let new = [7, 8];
/// let iter: std::vec::Splice<_> = v.splice(1.., new); /// let iter: std::vec::Splice<_> = v.splice(1.., new);
/// ``` /// ```
#[derive(Debug)] #[derive(Debug)]
pub struct Splice<'a, I: Iterator + 'a, A: Allocator + 'a = Global> { pub struct Splice<'a, I: Iterator + 'a, A: Allocator + 'a = Global> {
pub(super) drain: Drain<'a, I::Item, A>, pub(super) drain: Drain<'a, I::Item, A>,
pub(super) replace_with: I, pub(super) replace_with: I,
} }
impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> { impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
type Item = I::Item; type Item = I::Item;
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.drain.next() self.drain.next()
} }
#[inline(always)] #[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
self.drain.size_hint() self.drain.size_hint()
} }
} }
impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> { impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
#[inline(always)] #[inline(always)]
fn next_back(&mut self) -> Option<Self::Item> { fn next_back(&mut self) -> Option<Self::Item> {
self.drain.next_back() self.drain.next_back()
} }
} }
impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {} impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> { impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
#[inline] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
self.drain.by_ref().for_each(drop); self.drain.by_ref().for_each(drop);
unsafe { unsafe {
if self.drain.tail_len == 0 { if self.drain.tail_len == 0 {
self.drain.vec.as_mut().extend(self.replace_with.by_ref()); self.drain.vec.as_mut().extend(self.replace_with.by_ref());
return; return;
} }
// First fill the range left by drain(). // First fill the range left by drain().
if !self.drain.fill(&mut self.replace_with) { if !self.drain.fill(&mut self.replace_with) {
return; return;
} }
// There may be more elements. Use the lower bound as an estimate. // There may be more elements. Use the lower bound as an estimate.
// FIXME: Is the upper bound a better guess? Or something else? // FIXME: Is the upper bound a better guess? Or something else?
let (lower_bound, _upper_bound) = self.replace_with.size_hint(); let (lower_bound, _upper_bound) = self.replace_with.size_hint();
if lower_bound > 0 { if lower_bound > 0 {
self.drain.move_tail(lower_bound); self.drain.move_tail(lower_bound);
if !self.drain.fill(&mut self.replace_with) { if !self.drain.fill(&mut self.replace_with) {
return; return;
} }
} }
// Collect any remaining elements. // Collect any remaining elements.
// This is a zero-length vector which does not allocate if `lower_bound` was exact. // This is a zero-length vector which does not allocate if `lower_bound` was exact.
let mut collected = self let mut collected = self
.replace_with .replace_with
.by_ref() .by_ref()
.collect::<Vec<I::Item>>() .collect::<Vec<I::Item>>()
.into_iter(); .into_iter();
// Now we have an exact count. // Now we have an exact count.
if collected.len() > 0 { if collected.len() > 0 {
self.drain.move_tail(collected.len()); self.drain.move_tail(collected.len());
let filled = self.drain.fill(&mut collected); let filled = self.drain.fill(&mut collected);
debug_assert!(filled); debug_assert!(filled);
debug_assert_eq!(collected.len(), 0); debug_assert_eq!(collected.len(), 0);
} }
} }
// Let `Drain::drop` move the tail back if necessary and restore `vec.len`. // Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
} }
} }
/// Private helper methods for `Splice::drop` /// Private helper methods for `Splice::drop`
impl<T, A: Allocator> Drain<'_, T, A> { impl<T, A: Allocator> Drain<'_, T, A> {
/// The range from `self.vec.len` to `self.tail_start` contains elements /// The range from `self.vec.len` to `self.tail_start` contains elements
/// that have been moved out. /// that have been moved out.
/// Fill that range as much as possible with new elements from the `replace_with` iterator. /// Fill that range as much as possible with new elements from the `replace_with` iterator.
/// Returns `true` if we filled the entire range. (`replace_with.next()` didnt return `None`.) /// Returns `true` if we filled the entire range. (`replace_with.next()` didnt return `None`.)
#[inline(always)] #[inline(always)]
unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool { unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
let vec = unsafe { self.vec.as_mut() }; let vec = unsafe { self.vec.as_mut() };
let range_start = vec.len; let range_start = vec.len;
let range_end = self.tail_start; let range_end = self.tail_start;
let range_slice = unsafe { let range_slice = unsafe {
slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
}; };
for place in range_slice { for place in range_slice {
if let Some(new_item) = replace_with.next() { if let Some(new_item) = replace_with.next() {
unsafe { ptr::write(place, new_item) }; unsafe { ptr::write(place, new_item) };
vec.len += 1; vec.len += 1;
} else { } else {
return false; return false;
} }
} }
true true
} }
/// Makes room for inserting more elements before the tail. /// Makes room for inserting more elements before the tail.
#[inline(always)] #[inline(always)]
unsafe fn move_tail(&mut self, additional: usize) { unsafe fn move_tail(&mut self, additional: usize) {
let vec = unsafe { self.vec.as_mut() }; let vec = unsafe { self.vec.as_mut() };
let len = self.tail_start + self.tail_len; let len = self.tail_start + self.tail_len;
vec.buf.reserve(len, additional); vec.buf.reserve(len, additional);
let new_tail_start = self.tail_start + additional; let new_tail_start = self.tail_start + additional;
unsafe { unsafe {
let src = vec.as_ptr().add(self.tail_start); let src = vec.as_ptr().add(self.tail_start);
let dst = vec.as_mut_ptr().add(new_tail_start); let dst = vec.as_mut_ptr().add(new_tail_start);
ptr::copy(src, dst, self.tail_len); ptr::copy(src, dst, self.tail_len);
} }
self.tail_start = new_tail_start; self.tail_start = new_tail_start;
} }
} }

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"94ef33fb656ff0f7acc987633f36a283d36cec6662ba794051c11a73227d2853","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"0999fd320cdb3300dd22ff03b97cd41945cc9833a02a5b7c53ed36ab6d6f66e7","build.rs":"06f0353f62c32eac9942570b9163834e7ddcdc760d4bd4e7c2d98257bb0b647e","build/probe.rs":"b8b792036f13c9c1fbc6b1244198ea2305e61ddfcda3856563b581dcb1e1fe6e","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"f3bcaddc8665442611ae0f31ce7e9c19ede55d4a3022ffeb16f4c982bca7f018","src/chain.rs":"e83ee788dc5bb6bebba64356b35abbd5b624f2449d47e3716d02b2473fb8e5c5","src/context.rs":"04e4b80b9f6d8163edc53455b98ab0c40cb9ad104bcf0c74f8075f22024471ab","src/ensure.rs":"d4c2588608e529275bfee1c1afc8860d7def868ab01e95a692a995ee06b2936e","src/error.rs":"a274234af662770340b237c9016beea2f94e7906f3fe69d0d78057929889f25b","src/fmt.rs":"adf4be906b29900153bfb4b767a6049d58697dc3bcce7dfbb85ca773f5de5b33","src/kind.rs":"febaac378b8bfca7b95a76c9bf9fbd8ccdfd0cc1a6277cdc109a2cda5763f16e","src/lib.rs":"cd9e127c9762602cc86d81f7b4946248a108ab5e3dcd8bfd1c06fbffcadd6f69","src/macros.rs":"dd35f2ec2a0a25e4504fb04bcd42f6d0963bc0035aaaefc412f5ee1d78945fe1","src/ptr.rs":"4cb31d2f815b178daf951bfb94a1930383e056c0ca68d494603f45d8eea35d50","src/wrapper.rs":"4ffdf284d45fee90f11a48e59c493ed1114e1243903ceb265fa89cd4c8c0d338","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"ecccf9202a33611f64b76598806aa82abec2560ae058e32f63fb2fb3ef225be9","tests/test_backtrace.rs":"ed144f90bf62cc441de067f6cee09ece94bca9da8f9b492d11d3dc652ba83e26","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"3a8a8d7569913bd98c0e27c69d0bda35101e7fde7c056ed57cdd8ed018e4cbcb","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"89bb15f2a6288037bcf6ad976705038d9bea714da4244dee8314c720f88393c8","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"81b14dd207ba5fbf02aaed031646810906c9c9c2fc5cabffc8e88f82462be499","tests/test_macros.rs":"5172f82a6ad25b75f668f6419d161de3d12b8666d54701739fe33e86e4ddf148","tests/test_repr.rs":"034dee888abd08741e11ac2e95ef4fcb2ab3943d0a76e8e976db404658e1a252","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"315782f5f4246290fe190e3767b22c3dcaffaabc19c5ace0373537d53e765278","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"c2848c5f254b4c061eea6714d9baf709924aba06619eaf2a8b3aee1266b75f9e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"6f1fd1c620a1319e98b261e4a42b9346c28154310c5bb3dc6d6ded72fbdf638d","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"171f6c1c962503855480696e5d39e68946ec2a027b61a6f36ca1ad1b40265c5d","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"} {"files":{"Cargo.toml":"aa2d7538e2b3a969c60be518b72b524952d63b039811e8ab3791f1fbeb2645f5","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"6e608b9068b4ebab4b85944f047ea386f0288a99c615ac4a32ac45a7da4e5e33","build.rs":"22179bef46f3656c2436c97c2ac9751b26bbd04b67686ea6d75652aa92551fa7","build/probe.rs":"b8b792036f13c9c1fbc6b1244198ea2305e61ddfcda3856563b581dcb1e1fe6e","rust-toolchain.toml":"6bbb61302978c736b2da03e4fb40e3beab908f85d533ab46fd541e637b5f3e0f","src/backtrace.rs":"ea40abc828b93d01272c2d9f4254502ed34934e8c86fc2eac883dd972a09d8b2","src/chain.rs":"e83ee788dc5bb6bebba64356b35abbd5b624f2449d47e3716d02b2473fb8e5c5","src/context.rs":"04e4b80b9f6d8163edc53455b98ab0c40cb9ad104bcf0c74f8075f22024471ab","src/ensure.rs":"9763f418b5397764549866c111ec6db3a7bdc4c30ad95c3bbfc56c5434ea8c09","src/error.rs":"a274234af662770340b237c9016beea2f94e7906f3fe69d0d78057929889f25b","src/fmt.rs":"adf4be906b29900153bfb4b767a6049d58697dc3bcce7dfbb85ca773f5de5b33","src/kind.rs":"febaac378b8bfca7b95a76c9bf9fbd8ccdfd0cc1a6277cdc109a2cda5763f16e","src/lib.rs":"1c774243700f38ccaced1609c9e37a25c01f5e8aa900b876aef206207d6e4846","src/macros.rs":"17fb103e68a5befa768857314c3ca4d81d1dacfea0738bbb9c7597a485243499","src/ptr.rs":"4cb31d2f815b178daf951bfb94a1930383e056c0ca68d494603f45d8eea35d50","src/wrapper.rs":"4ffdf284d45fee90f11a48e59c493ed1114e1243903ceb265fa89cd4c8c0d338","tests/common/mod.rs":"f9088c2d7afafa64ff730b629272045b776bfafc2f5957508242da630635f2e1","tests/compiletest.rs":"022a8e400ef813d7ea1875b944549cee5125f6a995dc33e93b48cba3e1b57bd1","tests/drop/mod.rs":"08c3e553c1cc0d2dbd936fc45f4b5b1105057186affd6865e8d261e05f0f0646","tests/test_autotrait.rs":"ecccf9202a33611f64b76598806aa82abec2560ae058e32f63fb2fb3ef225be9","tests/test_backtrace.rs":"ed144f90bf62cc441de067f6cee09ece94bca9da8f9b492d11d3dc652ba83e26","tests/test_boxed.rs":"6b26db0e2eb72afe9af7352ea820837aab90f8d486294616dd5dc34c1b94038c","tests/test_chain.rs":"3a8a8d7569913bd98c0e27c69d0bda35101e7fde7c056ed57cdd8ed018e4cbcb","tests/test_context.rs":"8409c53b328562c11e822bd6c3cd17e0d4d50b9bbb8fc3617333fd77303a6a33","tests/test_convert.rs":"7e7a8b4772a427a911014ac4d1083f9519000e786177f898808980dd9bdfde61","tests/test_downcast.rs":"797e69a72d125758c4c4897e5dc776d549d52cc9a6a633e0a33193f588a62b88","tests/test_ensure.rs":"a9a21c72ebcafd76e159b0297fb51fe75b7323f65b46a1f8a9e015c9515abdb0","tests/test_ffi.rs":"d0cb4c1d6d9154090982dee72ae3ebe05a5981f976058c3250f1c9da5a45edef","tests/test_fmt.rs":"81b14dd207ba5fbf02aaed031646810906c9c9c2fc5cabffc8e88f82462be499","tests/test_macros.rs":"68673942662a43bceee62aaed69c25d7ddbc55e25d62d528e13033c3e2e756cd","tests/test_repr.rs":"034dee888abd08741e11ac2e95ef4fcb2ab3943d0a76e8e976db404658e1a252","tests/test_source.rs":"b80723cf635a4f8c4df21891b34bfab9ed2b2aa407e7a2f826d24e334cd5f88e","tests/ui/chained-comparison.rs":"6504b03d95b5acc232a7f4defc9f343b2be6733bf475fa0992e8e6545b912bd4","tests/ui/chained-comparison.stderr":"7f1d0a8c251b0ede2d30b3087ec157fc660945c97a642c4a5acf5a14ec58de34","tests/ui/empty-ensure.rs":"ab5bf37c846a0d689f26ce9257a27228411ed64154f9c950f1602d88a355d94b","tests/ui/empty-ensure.stderr":"315782f5f4246290fe190e3767b22c3dcaffaabc19c5ace0373537d53e765278","tests/ui/ensure-nonbool.rs":"7e57cb93fbcd82959b36586ed6bd2ad978b051fe5facd5274651fde6b1600905","tests/ui/ensure-nonbool.stderr":"0b4d1611e3bb65081bf38c1e49b1f12e5096738f276608661016e68f1fe13f7c","tests/ui/must-use.rs":"fb59860b43f673bf4a430a6036ba463e95028844d8dd4243cfe5ebc7f2be582f","tests/ui/must-use.stderr":"c2848c5f254b4c061eea6714d9baf709924aba06619eaf2a8b3aee1266b75f9e","tests/ui/no-impl.rs":"fab6cbf2f6ea510b86f567dfb3b7c31250a9fd71ae5d110dbb9188be569ec593","tests/ui/no-impl.stderr":"0d8ed712d25de898eae18cfdffc575a47f4d5596346058cf6cd50d016c4f8ce8","tests/ui/temporary-value.rs":"4dcc96271b2403e6372cf4cfc813445e5ce4365fc6e156b6bc38274098499a70","tests/ui/temporary-value.stderr":"171f6c1c962503855480696e5d39e68946ec2a027b61a6f36ca1ad1b40265c5d","tests/ui/wrong-interpolation.rs":"9c44d4674c2dccd27b9dedd03341346ec02d993b41793ee89b5755202e7e367e","tests/ui/wrong-interpolation.stderr":"301e60e2eb9401782c7dc0b3580613a4cb2aafd4cc8065734a630a62e1161aa5"},"package":"b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"}

View File

@ -13,8 +13,13 @@
edition = "2018" edition = "2018"
rust-version = "1.39" rust-version = "1.39"
name = "anyhow" name = "anyhow"
version = "1.0.81" version = "1.0.86"
authors = ["David Tolnay <dtolnay@gmail.com>"] authors = ["David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Flexible concrete Error type built on std::error::Error" description = "Flexible concrete Error type built on std::error::Error"
documentation = "https://docs.rs/anyhow" documentation = "https://docs.rs/anyhow"
readme = "README.md" readme = "README.md"
@ -38,8 +43,66 @@ rustdoc-args = [
targets = ["x86_64-unknown-linux-gnu"] targets = ["x86_64-unknown-linux-gnu"]
[lib] [lib]
name = "anyhow"
path = "src/lib.rs"
doc-scrape-examples = false doc-scrape-examples = false
[[test]]
name = "test_ensure"
path = "tests/test_ensure.rs"
[[test]]
name = "test_chain"
path = "tests/test_chain.rs"
[[test]]
name = "test_fmt"
path = "tests/test_fmt.rs"
[[test]]
name = "test_source"
path = "tests/test_source.rs"
[[test]]
name = "test_repr"
path = "tests/test_repr.rs"
[[test]]
name = "test_autotrait"
path = "tests/test_autotrait.rs"
[[test]]
name = "test_boxed"
path = "tests/test_boxed.rs"
[[test]]
name = "test_backtrace"
path = "tests/test_backtrace.rs"
[[test]]
name = "test_convert"
path = "tests/test_convert.rs"
[[test]]
name = "test_macros"
path = "tests/test_macros.rs"
[[test]]
name = "compiletest"
path = "tests/compiletest.rs"
[[test]]
name = "test_context"
path = "tests/test_context.rs"
[[test]]
name = "test_ffi"
path = "tests/test_ffi.rs"
[[test]]
name = "test_downcast"
path = "tests/test_downcast.rs"
[dependencies.backtrace] [dependencies.backtrace]
version = "0.3.51" version = "0.3.51"
optional = true optional = true

View File

@ -26,7 +26,7 @@ anyhow = "1.0"
return type of any fallible function. return type of any fallible function.
Within the function, use `?` to easily propagate any error that implements the Within the function, use `?` to easily propagate any error that implements the
`std::error::Error` trait. [`std::error::Error`] trait.
```rust ```rust
use anyhow::Result; use anyhow::Result;
@ -38,6 +38,8 @@ anyhow = "1.0"
} }
``` ```
[`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html
- Attach context to help the person troubleshooting the error understand where - Attach context to help the person troubleshooting the error understand where
things went wrong. A low-level error like "No such file or directory" can be things went wrong. A low-level error like "No such file or directory" can be
annoying to debug without more context about what higher level step the annoying to debug without more context about what higher level step the
@ -125,8 +127,8 @@ anyhow = "1.0"
## No-std support ## No-std support
In no_std mode, the same API is almost all available and works the same way. To In no_std mode, almost all of the same API is available and works the same way.
depend on Anyhow in no_std mode, disable our default enabled "std" feature in To depend on Anyhow in no_std mode, disable our default enabled "std" feature in
Cargo.toml. A global allocator is required. Cargo.toml. A global allocator is required.
```toml ```toml

View File

@ -1,5 +1,6 @@
use std::env; use std::env;
use std::ffi::OsString; use std::ffi::OsString;
use std::iter;
use std::path::Path; use std::path::Path;
use std::process::{self, Command, Stdio}; use std::process::{self, Command, Stdio};
use std::str; use std::str;
@ -64,6 +65,16 @@ fn main() {
None => return, None => return,
}; };
if rustc >= 80 {
println!("cargo:rustc-check-cfg=cfg(anyhow_nightly_testing)");
println!("cargo:rustc-check-cfg=cfg(anyhow_no_fmt_arguments_as_str)");
println!("cargo:rustc-check-cfg=cfg(anyhow_no_ptr_addr_of)");
println!("cargo:rustc-check-cfg=cfg(anyhow_no_unsafe_op_in_unsafe_fn_lint)");
println!("cargo:rustc-check-cfg=cfg(doc_cfg)");
println!("cargo:rustc-check-cfg=cfg(error_generic_member_access)");
println!("cargo:rustc-check-cfg=cfg(std_backtrace)");
}
if rustc < 51 { if rustc < 51 {
// core::ptr::addr_of // core::ptr::addr_of
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis // https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
@ -103,15 +114,15 @@ fn compile_probe(rustc_bootstrap: bool) -> bool {
let out_dir = cargo_env_var("OUT_DIR"); let out_dir = cargo_env_var("OUT_DIR");
let probefile = Path::new("build").join("probe.rs"); let probefile = Path::new("build").join("probe.rs");
// Make sure to pick up Cargo rustc configuration. let rustc_wrapper = env::var_os("RUSTC_WRAPPER").filter(|wrapper| !wrapper.is_empty());
let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") { let rustc_workspace_wrapper =
let mut cmd = Command::new(wrapper); env::var_os("RUSTC_WORKSPACE_WRAPPER").filter(|wrapper| !wrapper.is_empty());
// The wrapper's first argument is supposed to be the path to rustc. let mut rustc = rustc_wrapper
cmd.arg(rustc); .into_iter()
cmd .chain(rustc_workspace_wrapper)
} else { .chain(iter::once(rustc));
Command::new(rustc) let mut cmd = Command::new(rustc.next().unwrap());
}; cmd.args(rustc);
if !rustc_bootstrap { if !rustc_bootstrap {
cmd.env_remove("RUSTC_BOOTSTRAP"); cmd.env_remove("RUSTC_BOOTSTRAP");

View File

@ -65,7 +65,8 @@ macro_rules! backtrace_if_absent {
#[cfg(all(not(std_backtrace), feature = "backtrace"))] #[cfg(all(not(std_backtrace), feature = "backtrace"))]
mod capture { mod capture {
use alloc::borrow::Cow; use alloc::borrow::{Cow, ToOwned as _};
use alloc::vec::Vec;
use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName}; use backtrace::{BacktraceFmt, BytesOrWideString, Frame, PrintFmt, SymbolName};
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use core::fmt::{self, Debug, Display}; use core::fmt::{self, Debug, Display};

View File

@ -147,8 +147,8 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $let) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $let) $($parse)*} ($($rest)*) $($rest)*)
}; };
(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($life:tt $colon:tt $($dup:tt)*) $label:lifetime : $($rest:tt)*) => { (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($lifetime:tt $colon:tt $($dup:tt)*) $label:lifetime : $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $life $colon) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $lifetime $colon) $($parse)*} ($($rest)*) $($rest)*)
}; };
(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) &mut $($rest:tt)*) => { (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) &mut $($rest:tt)*) => {
@ -236,17 +236,17 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $const $block) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $const $block) $($parse)*} ($($rest)*) $($rest)*)
}; };
(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt $lit:literal $($rest:tt)*) => { (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($literal:tt $($dup:tt)*) $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $lit) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $literal) $($parse)*} ($($rest)*) $($rest)*)
}; };
// path expressions // path expressions
(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: $ident:ident $($rest:tt)*) => { (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(epath (atom $stack) $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(epath (atom $stack) $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt $ident:ident $($rest:tt)*) => { (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ident:tt $($dup:tt)*) $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(epath (atom $stack) $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(epath (atom $stack) $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -258,15 +258,19 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: << $($rest:tt)*) => { (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: << $($rest:tt)*) => {
$crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons <) $($parse)*} (< $($rest)*) < $($rest)*) $crate::__parse_ensure!(type (qpath (tpath (arglist (epath $stack)))) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: <- $($rest:tt)*) => { (epath $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt :: <- - $($rest:tt)*) => {
$crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons <) $($parse)*} (- $($rest)*) - $($rest)*) $crate::__fallback_ensure!($($bail)*)
}; };
(epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: $ident:ident $($rest:tt)*) => { (epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $larrow:tt $($dup:tt)*) :: <- $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(generic (epath $stack) $bail ($($fuel)*) {($($buf)* $colons $larrow) $($parse)*} ($($dup)*) $($dup)*)
};
(epath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(epath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(epath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -282,6 +286,10 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $bang $args) $($parse)*} ($($rest)*) $($rest)*)
}; };
(epath (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => {
$crate::__parse_ensure!($pop (split $stack) $bail ($($fuel)*) $parse $dup $($rest)*)
};
(epath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { (epath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) $parse $dup $($rest)*) $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) $parse $dup $($rest)*)
}; };
@ -308,18 +316,26 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons $langle) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $($dup:tt)*) . $i:ident :: << $($rest:tt)*) => { (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $langle:tt $($dup:tt)*) . $i:ident :: << $($rest:tt)*) => {
$crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons <) $($parse)*} (< $($rest)*) < $($rest)*) $crate::__parse_ensure!(type (qpath (tpath (arglist (atom $stack)))) $bail ($($fuel)*) {($($buf)* $dot $ident $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $($dup:tt)*) . $i:ident :: <- $($rest:tt)*) => { (atom $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt . $i:ident :: <- - $($rest:tt)*) => {
$crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons <) $($parse)*} (- $($rest)*) - $($rest)*) $crate::__fallback_ensure!($($bail)*)
}; };
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $($dup:tt)*) . $field:ident $($rest:tt)*) => { (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $ident:tt $colons:tt $larrow:tt $($dup:tt)*) . $i:ident :: <- $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* $dot $ident $colons $larrow) $($parse)*} ($($dup)*) $($dup)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $field:tt $($dup:tt)*) . $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $dot $field) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $dot $field) $($parse)*} ($($rest)*) $($rest)*)
}; };
(atom $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt . - $($rest:tt)*) => {
$crate::__fallback_ensure!($($bail)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $index:tt $($dup:tt)*) . $lit:literal $($rest:tt)*) => { (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($dot:tt $index:tt $($dup:tt)*) . $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $dot $index) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $dot $index) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -346,43 +362,51 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $star $mut) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $star $mut) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $life:lifetime $mut:tt $($dup:tt)*) & $l:lifetime mut $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $lifetime:tt $mut:tt $($dup:tt)*) & $l:lifetime mut $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $life $mut) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $lifetime $mut) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) & mut $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) & mut $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $mut) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $mut) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $life:lifetime $($dup:tt)*) & $l:lifetime $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $lifetime:tt $($dup:tt)*) & $l:lifetime $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $life) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $lifetime) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) & $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) & $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $life:lifetime $mut:tt $($dup:tt)*) && $l:lifetime mut $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $lifetime:tt $mut:tt $($dup:tt)*) && $l:lifetime mut $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $life $mut) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $lifetime $mut) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) && mut $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $mut:tt $($dup:tt)*) && mut $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $mut) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $mut) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $life:lifetime $($dup:tt)*) && $l:lifetime $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $lifetime:tt $($dup:tt)*) && $l:lifetime $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $life) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and $lifetime) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) && $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) && $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $and) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt unsafe extern - $($rest:tt)*) => {
$crate::__fallback_ensure!($($bail)*)
};
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($unsafe:tt $(extern $($abi:literal)?)? fn $($dup:tt)*) unsafe $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($unsafe:tt $(extern $($abi:literal)?)? fn $($dup:tt)*) unsafe $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $unsafe) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $unsafe) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($extern:tt $abi:literal fn $($dup:tt)*) extern $lit:literal $($rest:tt)*) => { (type $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt extern - $($rest:tt)*) => {
$crate::__fallback_ensure!($($bail)*)
};
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($extern:tt $abi:tt fn $($dup:tt)*) extern $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $extern $abi) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type $stack $bail ($($fuel)*) {($($buf)* $extern $abi) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -420,11 +444,11 @@ macro_rules! __parse_ensure {
// path types // path types
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: $ident:ident $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
(type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt $ident:ident $($rest:tt)*) => { (type $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ident:tt $($dup:tt)*) $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -436,27 +460,35 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt << $($rest:tt)*) => { (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($langle:tt $($dup:tt)*) << $($rest:tt)*) => {
$crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* <) $($parse)*} (< $($rest)*) < $($rest)*) $crate::__parse_ensure!(type (qpath (tpath (arglist (tpath $stack)))) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt <- $($rest:tt)*) => { (tpath $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt <- - $($rest:tt)*) => {
$crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* <) $($parse)*} (- $($rest)*) - $($rest)*) $crate::__fallback_ensure!($($bail)*)
};
(tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($larrow:tt $($dup:tt)*) <- $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $larrow) $($parse)*} ($($dup)*) $($dup)*)
}; };
(tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: < $($rest:tt)*) => { (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: < $($rest:tt)*) => {
$crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: << $($rest:tt)*) => { (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $langle:tt $($dup:tt)*) :: << $($rest:tt)*) => {
$crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons <) $($parse)*} (< $($rest)*) < $($rest)*) $crate::__parse_ensure!(type (qpath (tpath (arglist (tpath $stack)))) $bail ($($fuel)*) {($($buf)* $colons $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: <- $($rest:tt)*) => { (tpath $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt :: <- - $($rest:tt)*) => {
$crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons <) $($parse)*} (- $($rest)*) - $($rest)*) $crate::__fallback_ensure!($($bail)*)
}; };
(tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: $ident:ident $($rest:tt)*) => { (tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $larrow:tt $($dup:tt)*) :: <- $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(generic (tpath $stack) $bail ($($fuel)*) {($($buf)* $colons $larrow) $($parse)*} ($($dup)*) $($dup)*)
};
(tpath $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(tpath $stack $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -494,7 +526,11 @@ macro_rules! __parse_ensure {
// qualified paths // qualified paths
(qpath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $colons:tt $($dup:tt)*) > :: $ident:ident $($rest:tt)*) => { (qpath (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $colons:tt $ident:tt $($dup:tt)*) >> :: $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
};
(qpath ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $colons:tt $ident:tt $($dup:tt)*) > :: $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle $colons $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -504,41 +540,61 @@ macro_rules! __parse_ensure {
// trait objects // trait objects
(object (arglist $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($plus:tt $colons:tt $($dup:tt)*) + :: $ident:ident $($rest:tt)*) => { (object (arglist $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($plus:tt $colons:tt $ident:tt $($dup:tt)*) + :: $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(tpath (arglist $stack) $bail ($($fuel)*) {($($buf)* $plus $colons $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(tpath (arglist $stack) $bail ($($fuel)*) {($($buf)* $plus $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
(object (arglist $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($plus:tt $($dup:tt)*) + $ident:ident $($rest:tt)*) => { (object (arglist $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($plus:tt $ident:tt $($dup:tt)*) + $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(tpath (arglist $stack) $bail ($($fuel)*) {($($buf)* $plus $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(tpath (arglist $stack) $bail ($($fuel)*) {($($buf)* $plus $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
(object (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => {
$crate::__parse_ensure!($pop (split $stack) $bail ($($fuel)*) $parse $dup $($rest)*)
};
(object ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => { (object ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) $parse:tt $dup:tt $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) $parse $dup $($rest)*) $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) $parse $dup $($rest)*)
}; };
// angle bracketed generic arguments // angle bracketed generic arguments
(generic (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*)
};
(generic ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) > $($rest:tt)*) => { (generic ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) > $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(generic ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt >> $($rest:tt)*) => { (generic ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* >) $($parse)*} (> $($rest)*) > $($rest)*) $crate::__parse_ensure!($pop (split $stack) $bail ($($fuel)*) {($($buf)*) $($parse)*} ($rangle $($rest)*) $rangle $($rest)*)
}; };
(generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt $lit:literal $($rest:tt)*) => { (generic $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt - - $($rest:tt)*) => {
$crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $lit) $($parse)*} ($($rest)*) $($rest)*) $crate::__fallback_ensure!($($bail)*)
};
(generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($neg:tt $($dup:tt)*) - $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(generic $stack $bail ($($fuel)*) {($($buf)* $neg) $($parse)*} ($($dup)*) $($dup)*)
};
(generic $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt - $($rest:tt)*) => {
$crate::__fallback_ensure!($($bail)*)
};
(generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($literal:tt $($dup:tt)*) $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $literal) $($parse)*} ($($rest)*) $($rest)*)
}; };
(generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($brace:tt $($dup:tt)*) {$($block:tt)*} $($rest:tt)*) => { (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($brace:tt $($dup:tt)*) {$($block:tt)*} $($rest:tt)*) => {
$crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $brace) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $brace) $($parse)*} ($($rest)*) $($rest)*)
}; };
(generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt $life:lifetime $($rest:tt)*) => { (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($lifetime:tt $($dup:tt)*) $l:lifetime $($rest:tt)*) => {
$crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $life) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $lifetime) $($parse)*} ($($rest)*) $($rest)*)
}; };
(generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($assoc:ident $eq:tt $($dup:tt)*) $ident:ident = $($rest:tt)*) => { (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($assoc:tt $eq:tt $($dup:tt)*) $ident:ident = $($rest:tt)*) => {
$crate::__parse_ensure!(type (arglist $stack) $bail ($($fuel)*) {($($buf)* $assoc $eq) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type (arglist $stack) $bail ($($fuel)*) {($($buf)* $assoc $eq) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -550,12 +606,16 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(generic $stack $bail ($($fuel)*) {($($buf)* $comma) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(generic $stack $bail ($($fuel)*) {($($buf)* $comma) $($parse)*} ($($rest)*) $($rest)*)
}; };
(arglist (split ($pop:ident $stack:tt)) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)*) $rangle $($parse)*} ($($rest)*) $($rest)*)
};
(arglist ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) > $($rest:tt)*) => { (arglist ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) > $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*)
}; };
(arglist ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt >> $($rest:tt)*) => { (arglist ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => {
$crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* >) $($parse)*} (> $($rest)*) > $($rest)*) $crate::__parse_ensure!($pop (split $stack) $bail ($($fuel)*) {($($buf)*) $($parse)*} ($rangle $($rest)*) $rangle $($rest)*)
}; };
// patterns // patterns
@ -584,8 +644,20 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $at) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $at) $($parse)*} ($($rest)*) $($rest)*)
}; };
(pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt $lit:literal $($rest:tt)*) => { (pat $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt - - $($rest:tt)*) => {
$crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $lit) $($parse)*} ($($rest)*) $($rest)*) $crate::__fallback_ensure!($($bail)*)
};
(pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($neg:tt $($dup:tt)*) - $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $neg) $($parse)*} ($($dup)*) $($dup)*)
};
(pat $stack:tt ($($bail:tt)*) (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt - $($rest:tt)*) => {
$crate::__fallback_ensure!($($bail)*)
};
(pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($literal:tt $($dup:tt)*) $lit:literal $($rest:tt)*) => {
$crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $literal) $($parse)*} ($($rest)*) $($rest)*)
}; };
(pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($range:tt $($dup:tt)*) .. $($rest:tt)*) => { (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($range:tt $($dup:tt)*) .. $($rest:tt)*) => {
@ -620,11 +692,11 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $wild) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(pat $stack $bail ($($fuel)*) {($($buf)* $wild) $($parse)*} ($($rest)*) $($rest)*)
}; };
(pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $($dup:tt)*) :: $ident:ident $($rest:tt)*) => { (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($colons:tt $ident:tt $($dup:tt)*) :: $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(epath (pat $stack) $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(epath (pat $stack) $bail ($($fuel)*) {($($buf)* $colons $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
(pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt $ident:ident $($rest:tt)*) => { (pat $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($ident:tt $($dup:tt)*) $i:ident $($rest:tt)*) => {
$crate::__parse_ensure!(epath (pat $stack) $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(epath (pat $stack) $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} ($($rest)*) $($rest)*)
}; };
@ -632,48 +704,6 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(type (qpath (epath (pat $stack))) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(type (qpath (epath (pat $stack))) $bail ($($fuel)*) {($($buf)* $langle) $($parse)*} ($($rest)*) $($rest)*)
}; };
// high precedence binary operators
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($add:tt $($dup:tt)*) + $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $add) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($sub:tt $($dup:tt)*) - $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $sub) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($mul:tt $($dup:tt)*) * $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $mul) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($div:tt $($dup:tt)*) / $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $div) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rem:tt $($dup:tt)*) % $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $rem) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitxor:tt $($dup:tt)*) ^ $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitxor) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitand:tt $($dup:tt)*) & $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitand) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitor:tt $($dup:tt)*) | $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitor) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($shl:tt $($dup:tt)*) << $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $shl) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($shr:tt $($dup:tt)*) >> $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $shr) $($parse)*} ($($rest)*) $($rest)*)
};
// comparison binary operators // comparison binary operators
(atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($eq:tt $($dup:tt)*) == $($rest:tt)*) => { (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($eq:tt $($dup:tt)*) == $($rest:tt)*) => {
@ -716,14 +746,64 @@ macro_rules! __parse_ensure {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $ge) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $ge) $($parse)*} ($($rest)*) $($rest)*)
}; };
(atom (split ()) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $dup:tt >> $($rest:tt)*) => {
$crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)* > ) > } ($($rest)*) $($rest)*)
};
(atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($gt:tt $($dup:tt)*) > $($rest:tt)*) => { (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($gt:tt $($dup:tt)*) > $($rest:tt)*) => {
$crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) $gt} ($($rest)*) $($rest)*) $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) $gt} ($($rest)*) $($rest)*)
}; };
(atom (split $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($rangle:tt $($dup:tt)*) >> $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $rangle) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($gt:tt $($dup:tt)*) > $($rest:tt)*) => { (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} ($gt:tt $($dup:tt)*) > $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $gt) $($parse)*} ($($rest)*) $($rest)*) $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $gt) $($parse)*} ($($rest)*) $($rest)*)
}; };
// high precedence binary operators
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($add:tt $($dup:tt)*) + $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $add) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($sub:tt $($dup:tt)*) - $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $sub) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($mul:tt $($dup:tt)*) * $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $mul) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($div:tt $($dup:tt)*) / $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $div) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($rem:tt $($dup:tt)*) % $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $rem) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitxor:tt $($dup:tt)*) ^ $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitxor) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitand:tt $($dup:tt)*) & $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitand) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($bitor:tt $($dup:tt)*) | $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $bitor) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($shl:tt $($dup:tt)*) << $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $shl) $($parse)*} ($($rest)*) $($rest)*)
};
(atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($shr:tt $($dup:tt)*) >> $($rest:tt)*) => {
$crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $shr) $($parse)*} ($($rest)*) $($rest)*)
};
// low precedence binary operators // low precedence binary operators
(atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) && $($rest:tt)*) => { (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($and:tt $($dup:tt)*) && $($rest:tt)*) => {
@ -815,24 +895,24 @@ macro_rules! __fancy_ensure {
#[macro_export] #[macro_export]
macro_rules! __fallback_ensure { macro_rules! __fallback_ensure {
($cond:expr $(,)?) => { ($cond:expr $(,)?) => {
if !$cond { if $crate::__private::not($cond) {
return $crate::__private::Err($crate::Error::msg( return $crate::__private::Err($crate::Error::msg(
$crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`") $crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`")
)); ));
} }
}; };
($cond:expr, $msg:literal $(,)?) => { ($cond:expr, $msg:literal $(,)?) => {
if !$cond { if $crate::__private::not($cond) {
return $crate::__private::Err($crate::__anyhow!($msg)); return $crate::__private::Err($crate::__anyhow!($msg));
} }
}; };
($cond:expr, $err:expr $(,)?) => { ($cond:expr, $err:expr $(,)?) => {
if !$cond { if $crate::__private::not($cond) {
return $crate::__private::Err($crate::__anyhow!($err)); return $crate::__private::Err($crate::__anyhow!($err));
} }
}; };
($cond:expr, $fmt:expr, $($arg:tt)*) => { ($cond:expr, $fmt:expr, $($arg:tt)*) => {
if !$cond { if $crate::__private::not($cond) {
return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*)); return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*));
} }
}; };

View File

@ -17,7 +17,7 @@
//! the return type of any fallible function. //! the return type of any fallible function.
//! //!
//! Within the function, use `?` to easily propagate any error that implements //! Within the function, use `?` to easily propagate any error that implements
//! the `std::error::Error` trait. //! the [`std::error::Error`] trait.
//! //!
//! ``` //! ```
//! # pub trait Deserialize {} //! # pub trait Deserialize {}
@ -192,8 +192,8 @@
//! //!
//! # No-std support //! # No-std support
//! //!
//! In no_std mode, the same API is almost all available and works the same way. //! In no_std mode, almost all of the same API is available and works the same
//! To depend on Anyhow in no_std mode, disable our default enabled "std" //! way. To depend on Anyhow in no_std mode, disable our default enabled "std"
//! feature in Cargo.toml. A global allocator is required. //! feature in Cargo.toml. A global allocator is required.
//! //!
//! ```toml //! ```toml
@ -206,7 +206,7 @@
//! will require an explicit `.map_err(Error::msg)` when working with a //! will require an explicit `.map_err(Error::msg)` when working with a
//! non-Anyhow error type inside a function that returns Anyhow's error type. //! non-Anyhow error type inside a function that returns Anyhow's error type.
#![doc(html_root_url = "https://docs.rs/anyhow/1.0.81")] #![doc(html_root_url = "https://docs.rs/anyhow/1.0.85")]
#![cfg_attr(error_generic_member_access, feature(error_generic_member_access))] #![cfg_attr(error_generic_member_access, feature(error_generic_member_access))]
#![cfg_attr(doc_cfg, feature(doc_cfg))] #![cfg_attr(doc_cfg, feature(doc_cfg))]
#![no_std] #![no_std]
@ -383,7 +383,7 @@ pub use anyhow as format_err;
/// # Ok(()) /// # Ok(())
/// } /// }
/// ``` /// ```
#[cfg_attr(not(doc), repr(transparent))] #[repr(transparent)]
pub struct Error { pub struct Error {
inner: Own<ErrorImpl>, inner: Own<ErrorImpl>,
} }
@ -651,6 +651,7 @@ pub fn Ok<T>(t: T) -> Result<T> {
// Not public API. Referenced by macro-generated code. // Not public API. Referenced by macro-generated code.
#[doc(hidden)] #[doc(hidden)]
pub mod __private { pub mod __private {
use self::not::Bool;
use crate::Error; use crate::Error;
use alloc::fmt; use alloc::fmt;
use core::fmt::Arguments; use core::fmt::Arguments;
@ -699,4 +700,31 @@ pub mod __private {
pub fn must_use(error: Error) -> Error { pub fn must_use(error: Error) -> Error {
error error
} }
#[doc(hidden)]
#[inline]
pub fn not(cond: impl Bool) -> bool {
cond.not()
}
mod not {
#[doc(hidden)]
pub trait Bool {
fn not(self) -> bool;
}
impl Bool for bool {
#[inline]
fn not(self) -> bool {
!self
}
}
impl Bool for &bool {
#[inline]
fn not(self) -> bool {
!*self
}
}
}
} }

View File

@ -65,98 +65,108 @@ macro_rules! bail {
}; };
} }
/// Return early with an error if a condition is not satisfied. macro_rules! __ensure {
/// ($ensure:item) => {
/// This macro is equivalent to `if !$cond { return /// Return early with an error if a condition is not satisfied.
/// Err(`[`anyhow!($args...)`][anyhow!]`); }`. ///
/// /// This macro is equivalent to `if !$cond { return
/// The surrounding function's or closure's return value is required to be /// Err(`[`anyhow!($args...)`][anyhow!]`); }`.
/// `Result<_,`[`anyhow::Error`][crate::Error]`>`. ///
/// /// The surrounding function's or closure's return value is required to be
/// Analogously to `assert!`, `ensure!` takes a condition and exits the function /// `Result<_,`[`anyhow::Error`][crate::Error]`>`.
/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error` ///
/// rather than panicking. /// Analogously to `assert!`, `ensure!` takes a condition and exits the function
/// /// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`
/// [anyhow!]: crate::anyhow /// rather than panicking.
/// ///
/// # Example /// [anyhow!]: crate::anyhow
/// ///
/// ``` /// # Example
/// # use anyhow::{ensure, Result}; ///
/// # /// ```
/// # fn main() -> Result<()> { /// # use anyhow::{ensure, Result};
/// # let user = 0; /// #
/// # /// # fn main() -> Result<()> {
/// ensure!(user == 0, "only user 0 is allowed"); /// # let user = 0;
/// # Ok(()) /// #
/// # } /// ensure!(user == 0, "only user 0 is allowed");
/// ``` /// # Ok(())
/// /// # }
/// ``` /// ```
/// # use anyhow::{ensure, Result}; ///
/// # use thiserror::Error; /// ```
/// # /// # use anyhow::{ensure, Result};
/// # const MAX_DEPTH: usize = 1; /// # use thiserror::Error;
/// # /// #
/// #[derive(Error, Debug)] /// # const MAX_DEPTH: usize = 1;
/// enum ScienceError { /// #
/// #[error("recursion limit exceeded")] /// #[derive(Error, Debug)]
/// RecursionLimitExceeded, /// enum ScienceError {
/// # #[error("...")] /// #[error("recursion limit exceeded")]
/// # More = (stringify! { /// RecursionLimitExceeded,
/// ... /// # #[error("...")]
/// # }, 1).1, /// # More = (stringify! {
/// } /// ...
/// /// # }, 1).1,
/// # fn main() -> Result<()> { /// }
/// # let depth = 0; ///
/// # /// # fn main() -> Result<()> {
/// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded); /// # let depth = 0;
/// # Ok(()) /// #
/// # } /// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded);
/// ``` /// # Ok(())
#[cfg(doc)] /// # }
#[macro_export] /// ```
macro_rules! ensure { $ensure
($cond:expr $(,)?) => {
if !$cond {
return $crate::__private::Err($crate::Error::msg(
$crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`")
));
}
};
($cond:expr, $msg:literal $(,)?) => {
if !$cond {
return $crate::__private::Err($crate::__anyhow!($msg));
}
};
($cond:expr, $err:expr $(,)?) => {
if !$cond {
return $crate::__private::Err($crate::__anyhow!($err));
}
};
($cond:expr, $fmt:expr, $($arg:tt)*) => {
if !$cond {
return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*));
}
}; };
} }
#[cfg(doc)]
__ensure![
#[macro_export]
macro_rules! ensure {
($cond:expr $(,)?) => {
if !$cond {
return $crate::__private::Err($crate::Error::msg(
$crate::__private::concat!("Condition failed: `", $crate::__private::stringify!($cond), "`")
));
}
};
($cond:expr, $msg:literal $(,)?) => {
if !$cond {
return $crate::__private::Err($crate::__anyhow!($msg));
}
};
($cond:expr, $err:expr $(,)?) => {
if !$cond {
return $crate::__private::Err($crate::__anyhow!($err));
}
};
($cond:expr, $fmt:expr, $($arg:tt)*) => {
if !$cond {
return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*));
}
};
}
];
#[cfg(not(doc))] #[cfg(not(doc))]
#[macro_export] __ensure![
macro_rules! ensure { #[macro_export]
($($tt:tt)*) => { macro_rules! ensure {
$crate::__parse_ensure!( ($($tt:tt)*) => {
/* state */ 0 $crate::__parse_ensure!(
/* stack */ () /* state */ 0
/* bail */ ($($tt)*) /* stack */ ()
/* fuel */ (~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~) /* bail */ ($($tt)*)
/* parse */ {()} /* fuel */ (~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~)
/* dup */ ($($tt)*) /* parse */ {()}
/* rest */ $($tt)* /* dup */ ($($tt)*)
) /* rest */ $($tt)*
}; )
} };
}
];
/// Construct an ad-hoc error from a string or existing non-`anyhow` error /// Construct an ad-hoc error from a string or existing non-`anyhow` error
/// value. /// value.

View File

@ -1,6 +1,9 @@
#![allow( #![allow(
clippy::bool_to_int_with_if, clippy::bool_to_int_with_if,
clippy::char_lit_as_u8,
clippy::deref_addrof,
clippy::diverging_sub_expression, clippy::diverging_sub_expression,
clippy::erasing_op,
clippy::extra_unused_type_parameters, clippy::extra_unused_type_parameters,
clippy::if_same_then_else, clippy::if_same_then_else,
clippy::ifs_same_cond, clippy::ifs_same_cond,
@ -16,6 +19,7 @@
clippy::redundant_pattern_matching, clippy::redundant_pattern_matching,
clippy::too_many_lines, clippy::too_many_lines,
clippy::unit_arg, clippy::unit_arg,
clippy::unnecessary_cast,
clippy::while_immutable_condition, clippy::while_immutable_condition,
clippy::zero_ptr, clippy::zero_ptr,
irrefutable_let_patterns irrefutable_let_patterns
@ -128,6 +132,19 @@ fn test_low_precedence_binary_operator() {
test, test,
"Condition failed: `while false == true && false {} < ()` (() vs ())", "Condition failed: `while false == true && false {} < ()` (() vs ())",
); );
let a = 15;
let b = 3;
let test = || Ok(ensure!(a <= b || a - b <= 10));
assert_err(test, "Condition failed: `a <= b || a - b <= 10`");
}
#[test]
fn test_high_precedence_binary_operator() {
let a = 15;
let b = 3;
let test = || Ok(ensure!(a - b <= 10));
assert_err(test, "Condition failed: `a - b <= 10` (12 vs 10)");
} }
#[test] #[test]
@ -464,7 +481,9 @@ fn test_trailer() {
fn test_whitespace() { fn test_whitespace() {
#[derive(Debug)] #[derive(Debug)]
pub struct Point { pub struct Point {
#[allow(dead_code)]
pub x: i32, pub x: i32,
#[allow(dead_code)]
pub y: i32, pub y: i32,
} }

View File

@ -3,6 +3,7 @@
clippy::eq_op, clippy::eq_op,
clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257 clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12257
clippy::items_after_statements, clippy::items_after_statements,
clippy::match_single_binding,
clippy::needless_pass_by_value, clippy::needless_pass_by_value,
clippy::shadow_unrelated, clippy::shadow_unrelated,
clippy::wildcard_imports clippy::wildcard_imports
@ -11,7 +12,7 @@
mod common; mod common;
use self::common::*; use self::common::*;
use anyhow::{anyhow, ensure}; use anyhow::{anyhow, ensure, Result};
use std::cell::Cell; use std::cell::Cell;
use std::future; use std::future;
@ -53,6 +54,20 @@ fn test_ensure() {
); );
} }
#[test]
fn test_ensure_nonbool() -> Result<()> {
struct Struct {
condition: bool,
}
let s = Struct { condition: true };
match &s {
Struct { condition } => ensure!(condition), // &bool
}
Ok(())
}
#[test] #[test]
fn test_temporaries() { fn test_temporaries() {
fn require_send_sync(_: impl Send + Sync) {} fn require_send_sync(_: impl Send + Sync) {}

View File

@ -0,0 +1,40 @@
use anyhow::{ensure, Result};
use std::ops::{Deref, Not};
struct Bool(bool);
struct DerefBool(bool);
struct NotBool(bool);
impl Deref for DerefBool {
type Target = bool;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Not for NotBool {
type Output = bool;
fn not(self) -> Self::Output {
!self.0
}
}
fn main() -> Result<()> {
ensure!("...");
let mut s = Bool(true);
match &mut s {
Bool(cond) => ensure!(cond),
}
let db = DerefBool(true);
ensure!(db);
ensure!(&db);
let nb = NotBool(true);
ensure!(nb);
Ok(())
}

View File

@ -0,0 +1,91 @@
error[E0277]: the trait bound `&str: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:25:13
|
25 | ensure!("...");
| --------^^^^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `&str`
| required by a bound introduced by this call
|
= help: the following other types implement trait `__private::not::Bool`:
&bool
bool
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`
error[E0277]: the trait bound `&mut bool: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:29:31
|
29 | Bool(cond) => ensure!(cond),
| --------^^^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `&mut bool`
| required by a bound introduced by this call
|
= help: the following other types implement trait `__private::not::Bool`:
&bool
bool
= note: `__private::not::Bool` is implemented for `&bool`, but not for `&mut bool`
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`
error[E0277]: the trait bound `DerefBool: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:33:13
|
33 | ensure!(db);
| --------^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `DerefBool`
| required by a bound introduced by this call
|
= help: the following other types implement trait `__private::not::Bool`:
&bool
bool
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`
error[E0277]: the trait bound `&DerefBool: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:34:13
|
34 | ensure!(&db);
| --------^^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `&DerefBool`
| required by a bound introduced by this call
|
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`
help: consider dereferencing here
|
34 | ensure!(&*db);
| +
error[E0277]: the trait bound `NotBool: __private::not::Bool` is not satisfied
--> tests/ui/ensure-nonbool.rs:37:13
|
37 | ensure!(nb);
| --------^^-
| | |
| | the trait `__private::not::Bool` is not implemented for `NotBool`
| required by a bound introduced by this call
|
= help: the following other types implement trait `__private::not::Bool`:
&bool
bool
note: required by a bound in `anyhow::__private::not`
--> src/lib.rs
|
| pub fn not(cond: impl Bool) -> bool {
| ^^^^ required by this bound in `not`

View File

@ -27,6 +27,6 @@ note: the traits `Into` and `std::fmt::Display` must be implemented
= help: items from traits can only be used if the trait is implemented and in scope = help: items from traits can only be used if the trait is implemented and in scope
= note: the following traits define an item `anyhow_kind`, perhaps you need to implement one of them: = note: the following traits define an item `anyhow_kind`, perhaps you need to implement one of them:
candidate #1: `anyhow::kind::AdhocKind` candidate #1: `anyhow::kind::AdhocKind`
candidate #2: `anyhow::kind::TraitKind` candidate #2: `anyhow::kind::BoxedKind`
candidate #3: `anyhow::kind::BoxedKind` candidate #3: `anyhow::kind::TraitKind`
= note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `anyhow` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -1 +1 @@
{"files":{"Cargo.lock":"400a67d2fb1c1dc7160f7730a36ae05b398af392ac270980f00e87f659e2a6e0","Cargo.toml":"1a4d6915017b2461f8037a320bcc62b424fcb866e77bf4da5dfce1e5a03f84ca","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac","README.md":"62e4f60d7b6f393dd36f06f348560dbbc871de6fb1cbcfcaec34fa1d9527f81b","examples/integers.rs":"589ff4271566dfa322becddf3e2c7b592e6e0bc97b02892ce75619b7e452e930","examples/paths.rs":"1b30e466b824ce8df7ad0a55334424131d9d2573d6cf9f7d5d50c09c8901d526","examples/traits.rs":"cbee6a3e1f7db60b02ae25b714926517144a77cb492021f492774cf0e1865a9e","examples/versions.rs":"38535e6d9f5bfae0de474a3db79a40e8f5da8ba9334c5ff4c363de9bc99d4d12","src/error.rs":"12de7dafea4a35d1dc2f0fa79bfa038386bbbea72bf083979f4ddf227999eeda","src/lib.rs":"07f24132bbed72428d468fddd40b8753b53d57d15d1b31288531672c1a5ab07d","src/tests.rs":"f0e6dc1ad9223c0336c02e215ea3940acb2af6c3bc8fd791e16cd4e786e6a608","src/version.rs":"f1d457d44b6868b4690db795f7b67edfb25c29c6227381b43dcc5452716f2828","tests/no_std.rs":"cc5619466c6e955552f30ed2f80ba8ddf45c3d5d257f628f54dedc0da978f6aa","tests/rustflags.rs":"5c8169b88216055019db61b5d7baf4abdf675e3b14b54f5037bb1e3acd0a5d3f","tests/wrappers.rs":"1ace81fc706f0592647d6aa5bdd854a8e15fa2b6dcd4444334b4a5767ca7fd2c"},"package":"f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"} {"files":{"Cargo.lock":"8e60b691c883629c1e19c8dad7c4c18cded1a85c2e8f2e2a77e7a96957f865a7","Cargo.toml":"f8c2d5675773b7ddff8801c3c17ff9d26e9632fe2027a6b81ceb7bda67d71bfd","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac","README.md":"51238410cbbb06b149a794d954ff4d5943da566a97e71dc3aa8b5fa5a9b538b6","examples/integers.rs":"589ff4271566dfa322becddf3e2c7b592e6e0bc97b02892ce75619b7e452e930","examples/nightly.rs":"ac8b5a9aa1e04465e44f5053b3c899b635e07af058c73aa8b45176bf4b5912f9","examples/paths.rs":"1b30e466b824ce8df7ad0a55334424131d9d2573d6cf9f7d5d50c09c8901d526","examples/traits.rs":"cbee6a3e1f7db60b02ae25b714926517144a77cb492021f492774cf0e1865a9e","examples/versions.rs":"38535e6d9f5bfae0de474a3db79a40e8f5da8ba9334c5ff4c363de9bc99d4d12","src/error.rs":"fd8ff67c64f7cd1b9f81325a81de4baa34c39d6ae298bdb33f9829cc91acac39","src/lib.rs":"7b00cd501b52bab797bf047ada2a446e16fc2b8b05567670d8b8b7ada3179f55","src/rustc.rs":"a8a213ddb64a05c1a1af933bcb331a98879e942b167c33d8f94f9f60ebb14e29","src/tests.rs":"594a1cff6fef4a0f8b5f962a668fda4030db5005f37f01eeb06d692fc48a60df","src/version.rs":"4f7d23b36f01c7be1871be86c038d6cb4689e145d67c82d3793690e9aa05b133","tests/no_std.rs":"cc5619466c6e955552f30ed2f80ba8ddf45c3d5d257f628f54dedc0da978f6aa","tests/rustflags.rs":"5c8169b88216055019db61b5d7baf4abdf675e3b14b54f5037bb1e3acd0a5d3f","tests/wrap_ignored":"a9e241edf584a0702066b25bc15c5bbfd8a1019e14fb655fc4f47a67360065ca","tests/wrappers.rs":"e8eb0eb5ac28ecd9e3473b5ddc321b1d4d523a6fb0c072255ac37d40674aa35c"},"package":"0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"}

5
pve-rs/vendor/autocfg/Cargo.lock generated vendored
View File

@ -1,6 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.2.0" version = "1.3.0"

View File

@ -12,7 +12,7 @@
[package] [package]
rust-version = "1.0" rust-version = "1.0"
name = "autocfg" name = "autocfg"
version = "1.2.0" version = "1.3.0"
authors = ["Josh Stone <cuviper@gmail.com>"] authors = ["Josh Stone <cuviper@gmail.com>"]
exclude = ["/.github/**"] exclude = ["/.github/**"]
description = "Automatic cfg for Rust compiler features" description = "Automatic cfg for Rust compiler features"

View File

@ -43,6 +43,11 @@ should only be used when the compiler supports it.
## Release Notes ## Release Notes
- 1.3.0 (2024-05-03)
- Add `probe_raw` for direct control of the code that will be test-compiled.
- Use wrappers when querying the `rustc` version information too.
- 1.2.0 (2024-03-25) - 1.2.0 (2024-03-25)
- Add `no_std` and `set_no_std` to control the use of `#![no_std]` in probes. - Add `no_std` and `set_no_std` to control the use of `#![no_std]` in probes.

View File

@ -0,0 +1,18 @@
extern crate autocfg;
fn main() {
// Normally, cargo will set `OUT_DIR` for build scripts.
let ac = autocfg::AutoCfg::with_dir("target").unwrap();
// When this feature was stabilized, it also renamed the method to
// `chunk_by`, so it's important to *use* the feature in your probe.
let code = r#"
#![feature(slice_group_by)]
pub fn probe(slice: &[i32]) -> impl Iterator<Item = &[i32]> {
slice.group_by(|a, b| a == b)
}
"#;
if ac.probe_raw(code).is_ok() {
autocfg::emit("has_slice_group_by");
}
}

View File

@ -2,6 +2,7 @@ use std::error;
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::num; use std::num;
use std::process;
use std::str; use std::str;
/// A common error type for the `autocfg` crate. /// A common error type for the `autocfg` crate.
@ -20,7 +21,7 @@ impl error::Error for Error {
ErrorKind::Io(ref e) => Some(e), ErrorKind::Io(ref e) => Some(e),
ErrorKind::Num(ref e) => Some(e), ErrorKind::Num(ref e) => Some(e),
ErrorKind::Utf8(ref e) => Some(e), ErrorKind::Utf8(ref e) => Some(e),
ErrorKind::Other(_) => None, ErrorKind::Process(_) | ErrorKind::Other(_) => None,
} }
} }
} }
@ -31,6 +32,10 @@ impl fmt::Display for Error {
ErrorKind::Io(ref e) => e.fmt(f), ErrorKind::Io(ref e) => e.fmt(f),
ErrorKind::Num(ref e) => e.fmt(f), ErrorKind::Num(ref e) => e.fmt(f),
ErrorKind::Utf8(ref e) => e.fmt(f), ErrorKind::Utf8(ref e) => e.fmt(f),
ErrorKind::Process(ref status) => {
// Same message as the newer `ExitStatusError`
write!(f, "process exited unsuccessfully: {}", status)
}
ErrorKind::Other(s) => s.fmt(f), ErrorKind::Other(s) => s.fmt(f),
} }
} }
@ -40,10 +45,17 @@ impl fmt::Display for Error {
enum ErrorKind { enum ErrorKind {
Io(io::Error), Io(io::Error),
Num(num::ParseIntError), Num(num::ParseIntError),
Process(process::ExitStatus),
Utf8(str::Utf8Error), Utf8(str::Utf8Error),
Other(&'static str), Other(&'static str),
} }
pub fn from_exit(status: process::ExitStatus) -> Error {
Error {
kind: ErrorKind::Process(status),
}
}
pub fn from_io(e: io::Error) -> Error { pub fn from_io(e: io::Error) -> Error {
Error { Error {
kind: ErrorKind::Io(e), kind: ErrorKind::Io(e),

View File

@ -61,10 +61,11 @@ macro_rules! try {
use std::env; use std::env;
use std::ffi::OsString; use std::ffi::OsString;
use std::fmt::Arguments;
use std::fs; use std::fs;
use std::io::{stderr, Write}; use std::io::{stderr, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{Command, Stdio}; use std::process::Stdio;
#[allow(deprecated)] #[allow(deprecated)]
use std::sync::atomic::ATOMIC_USIZE_INIT; use std::sync::atomic::ATOMIC_USIZE_INIT;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
@ -72,6 +73,9 @@ use std::sync::atomic::{AtomicUsize, Ordering};
mod error; mod error;
pub use error::Error; pub use error::Error;
mod rustc;
use rustc::Rustc;
mod version; mod version;
use version::Version; use version::Version;
@ -82,9 +86,7 @@ mod tests;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct AutoCfg { pub struct AutoCfg {
out_dir: PathBuf, out_dir: PathBuf,
rustc: PathBuf, rustc: Rustc,
rustc_wrapper: Option<PathBuf>,
rustc_workspace_wrapper: Option<PathBuf>,
rustc_version: Version, rustc_version: Version,
target: Option<OsString>, target: Option<OsString>,
no_std: bool, no_std: bool,
@ -155,9 +157,8 @@ impl AutoCfg {
/// - `dir` is not a writable directory. /// - `dir` is not a writable directory.
/// ///
pub fn with_dir<T: Into<PathBuf>>(dir: T) -> Result<Self, Error> { pub fn with_dir<T: Into<PathBuf>>(dir: T) -> Result<Self, Error> {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); let rustc = Rustc::new();
let rustc: PathBuf = rustc.into(); let rustc_version = try!(rustc.version());
let rustc_version = try!(Version::from_rustc(&rustc));
let target = env::var_os("TARGET"); let target = env::var_os("TARGET");
@ -170,8 +171,6 @@ impl AutoCfg {
let mut ac = AutoCfg { let mut ac = AutoCfg {
rustflags: rustflags(&target, &dir), rustflags: rustflags(&target, &dir),
rustc_wrapper: get_rustc_wrapper(false),
rustc_workspace_wrapper: get_rustc_wrapper(true),
out_dir: dir, out_dir: dir,
rustc: rustc, rustc: rustc,
rustc_version: rustc_version, rustc_version: rustc_version,
@ -180,11 +179,11 @@ impl AutoCfg {
}; };
// Sanity check with and without `std`. // Sanity check with and without `std`.
if !ac.probe("").unwrap_or(false) { if !ac.probe_raw("").is_ok() {
ac.no_std = true; if ac.probe_raw("#![no_std]").is_ok() {
if !ac.probe("").unwrap_or(false) { ac.no_std = true;
} else {
// Neither worked, so assume nothing... // Neither worked, so assume nothing...
ac.no_std = false;
let warning = b"warning: autocfg could not probe for `std`\n"; let warning = b"warning: autocfg could not probe for `std`\n";
stderr().write_all(warning).ok(); stderr().write_all(warning).ok();
} }
@ -207,7 +206,7 @@ impl AutoCfg {
/// ///
/// See also [`set_no_std`](#method.set_no_std). /// See also [`set_no_std`](#method.set_no_std).
/// ///
/// [prelude]: https://doc.rust-lang.org/reference/crates-and-source-files.html#preludes-and-no_std /// [prelude]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute
pub fn no_std(&self) -> bool { pub fn no_std(&self) -> bool {
self.no_std self.no_std
} }
@ -233,23 +232,13 @@ impl AutoCfg {
} }
} }
fn probe<T: AsRef<[u8]>>(&self, code: T) -> Result<bool, Error> { fn probe_fmt<'a>(&self, source: Arguments<'a>) -> Result<(), Error> {
#[allow(deprecated)] #[allow(deprecated)]
static ID: AtomicUsize = ATOMIC_USIZE_INIT; static ID: AtomicUsize = ATOMIC_USIZE_INIT;
let id = ID.fetch_add(1, Ordering::Relaxed); let id = ID.fetch_add(1, Ordering::Relaxed);
// Build the command with possible wrappers. let mut command = self.rustc.command();
let mut rustc = self
.rustc_wrapper
.iter()
.chain(self.rustc_workspace_wrapper.iter())
.chain(Some(&self.rustc));
let mut command = Command::new(rustc.next().unwrap());
for arg in rustc {
command.arg(arg);
}
command command
.arg("--crate-name") .arg("--crate-name")
.arg(format!("probe{}", id)) .arg(format!("probe{}", id))
@ -268,14 +257,69 @@ impl AutoCfg {
let mut child = try!(command.spawn().map_err(error::from_io)); let mut child = try!(command.spawn().map_err(error::from_io));
let mut stdin = child.stdin.take().expect("rustc stdin"); let mut stdin = child.stdin.take().expect("rustc stdin");
if self.no_std { try!(stdin.write_fmt(source).map_err(error::from_io));
try!(stdin.write_all(b"#![no_std]\n").map_err(error::from_io));
}
try!(stdin.write_all(code.as_ref()).map_err(error::from_io));
drop(stdin); drop(stdin);
let status = try!(child.wait().map_err(error::from_io)); match child.wait() {
Ok(status.success()) Ok(status) if status.success() => Ok(()),
Ok(status) => Err(error::from_exit(status)),
Err(error) => Err(error::from_io(error)),
}
}
fn probe<'a>(&self, code: Arguments<'a>) -> bool {
let result = if self.no_std {
self.probe_fmt(format_args!("#![no_std]\n{}", code))
} else {
self.probe_fmt(code)
};
result.is_ok()
}
/// Tests whether the given code can be compiled as a Rust library.
///
/// This will only return `Ok` if the compiler ran and exited successfully,
/// per `ExitStatus::success()`.
/// The code is passed to the compiler exactly as-is, notably not even
/// adding the [`#![no_std]`][Self::no_std] attribute like other probes.
///
/// Raw probes are useful for testing functionality that's not yet covered
/// by the rest of the `AutoCfg` API. For example, the following attribute
/// **must** be used at the crate level, so it wouldn't work within the code
/// templates used by other `probe_*` methods.
///
/// ```
/// # extern crate autocfg;
/// # // Normally, cargo will set `OUT_DIR` for build scripts.
/// # std::env::set_var("OUT_DIR", "target");
/// let ac = autocfg::new();
/// assert!(ac.probe_raw("#![no_builtins]").is_ok());
/// ```
///
/// Rust nightly features could be tested as well -- ideally including a
/// code sample to ensure the unstable feature still works as expected.
/// For example, `slice::group_by` was renamed to `chunk_by` when it was
/// stabilized, even though the feature name was unchanged, so testing the
/// `#![feature(..)]` alone wouldn't reveal that. For larger snippets,
/// [`include_str!`] may be useful to load them from separate files.
///
/// ```
/// # extern crate autocfg;
/// # // Normally, cargo will set `OUT_DIR` for build scripts.
/// # std::env::set_var("OUT_DIR", "target");
/// let ac = autocfg::new();
/// let code = r#"
/// #![feature(slice_group_by)]
/// pub fn probe(slice: &[i32]) -> impl Iterator<Item = &[i32]> {
/// slice.group_by(|a, b| a == b)
/// }
/// "#;
/// if ac.probe_raw(code).is_ok() {
/// autocfg::emit("has_slice_group_by");
/// }
/// ```
pub fn probe_raw(&self, code: &str) -> Result<(), Error> {
self.probe_fmt(format_args!("{}", code))
} }
/// Tests whether the given sysroot crate can be used. /// Tests whether the given sysroot crate can be used.
@ -286,8 +330,8 @@ impl AutoCfg {
/// extern crate CRATE as probe; /// extern crate CRATE as probe;
/// ``` /// ```
pub fn probe_sysroot_crate(&self, name: &str) -> bool { pub fn probe_sysroot_crate(&self, name: &str) -> bool {
self.probe(format!("extern crate {} as probe;", name)) // `as _` wasn't stabilized until Rust 1.33 // Note: `as _` wasn't stabilized until Rust 1.33
.unwrap_or(false) self.probe(format_args!("extern crate {} as probe;", name))
} }
/// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true. /// Emits a config value `has_CRATE` if `probe_sysroot_crate` returns true.
@ -305,7 +349,7 @@ impl AutoCfg {
/// pub use PATH; /// pub use PATH;
/// ``` /// ```
pub fn probe_path(&self, path: &str) -> bool { pub fn probe_path(&self, path: &str) -> bool {
self.probe(format!("pub use {};", path)).unwrap_or(false) self.probe(format_args!("pub use {};", path))
} }
/// Emits a config value `has_PATH` if `probe_path` returns true. /// Emits a config value `has_PATH` if `probe_path` returns true.
@ -333,8 +377,7 @@ impl AutoCfg {
/// pub trait Probe: TRAIT + Sized {} /// pub trait Probe: TRAIT + Sized {}
/// ``` /// ```
pub fn probe_trait(&self, name: &str) -> bool { pub fn probe_trait(&self, name: &str) -> bool {
self.probe(format!("pub trait Probe: {} + Sized {{}}", name)) self.probe(format_args!("pub trait Probe: {} + Sized {{}}", name))
.unwrap_or(false)
} }
/// Emits a config value `has_TRAIT` if `probe_trait` returns true. /// Emits a config value `has_TRAIT` if `probe_trait` returns true.
@ -362,8 +405,7 @@ impl AutoCfg {
/// pub type Probe = TYPE; /// pub type Probe = TYPE;
/// ``` /// ```
pub fn probe_type(&self, name: &str) -> bool { pub fn probe_type(&self, name: &str) -> bool {
self.probe(format!("pub type Probe = {};", name)) self.probe(format_args!("pub type Probe = {};", name))
.unwrap_or(false)
} }
/// Emits a config value `has_TYPE` if `probe_type` returns true. /// Emits a config value `has_TYPE` if `probe_type` returns true.
@ -391,8 +433,7 @@ impl AutoCfg {
/// pub fn probe() { let _ = EXPR; } /// pub fn probe() { let _ = EXPR; }
/// ``` /// ```
pub fn probe_expression(&self, expr: &str) -> bool { pub fn probe_expression(&self, expr: &str) -> bool {
self.probe(format!("pub fn probe() {{ let _ = {}; }}", expr)) self.probe(format_args!("pub fn probe() {{ let _ = {}; }}", expr))
.unwrap_or(false)
} }
/// Emits the given `cfg` value if `probe_expression` returns true. /// Emits the given `cfg` value if `probe_expression` returns true.
@ -410,8 +451,7 @@ impl AutoCfg {
/// pub const PROBE: () = ((), EXPR).0; /// pub const PROBE: () = ((), EXPR).0;
/// ``` /// ```
pub fn probe_constant(&self, expr: &str) -> bool { pub fn probe_constant(&self, expr: &str) -> bool {
self.probe(format!("pub const PROBE: () = ((), {}).0;", expr)) self.probe(format_args!("pub const PROBE: () = ((), {}).0;", expr))
.unwrap_or(false)
} }
/// Emits the given `cfg` value if `probe_constant` returns true. /// Emits the given `cfg` value if `probe_constant` returns true.
@ -493,27 +533,3 @@ fn rustflags(target: &Option<OsString>, dir: &Path) -> Vec<String> {
Vec::new() Vec::new()
} }
fn get_rustc_wrapper(workspace: bool) -> Option<PathBuf> {
// We didn't really know whether the workspace wrapper is applicable until Cargo started
// deliberately setting or unsetting it in rust-lang/cargo#9601. We'll use the encoded
// rustflags as a proxy for that change for now, but we could instead check version 1.55.
if workspace && env::var_os("CARGO_ENCODED_RUSTFLAGS").is_none() {
return None;
}
let name = if workspace {
"RUSTC_WORKSPACE_WRAPPER"
} else {
"RUSTC_WRAPPER"
};
if let Some(wrapper) = env::var_os(name) {
// NB: `OsStr` didn't get `len` or `is_empty` until 1.9.
if wrapper != OsString::new() {
return Some(wrapper.into());
}
}
None
}

89
pve-rs/vendor/autocfg/src/rustc.rs vendored Normal file
View File

@ -0,0 +1,89 @@
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::Command;
use super::error::Error;
use super::version::Version;
#[derive(Clone, Debug)]
pub struct Rustc {
rustc: PathBuf,
rustc_wrapper: Option<PathBuf>,
rustc_workspace_wrapper: Option<PathBuf>,
}
impl Rustc {
pub fn new() -> Self {
Rustc {
rustc: env::var_os("RUSTC")
.unwrap_or_else(|| "rustc".into())
.into(),
rustc_wrapper: get_rustc_wrapper(false),
rustc_workspace_wrapper: get_rustc_wrapper(true),
}
}
/// Build the command with possible wrappers.
pub fn command(&self) -> Command {
let mut rustc = self
.rustc_wrapper
.iter()
.chain(self.rustc_workspace_wrapper.iter())
.chain(Some(&self.rustc));
let mut command = Command::new(rustc.next().unwrap());
for arg in rustc {
command.arg(arg);
}
command
}
/// Try to get the `rustc` version.
pub fn version(&self) -> Result<Version, Error> {
// Some wrappers like clippy-driver don't pass through version commands,
// so we try to fall back to combinations without each wrapper.
macro_rules! try_version {
($command:expr) => {
if let Ok(value) = Version::from_command($command) {
return Ok(value);
}
};
}
let rustc = &self.rustc;
if let Some(ref rw) = self.rustc_wrapper {
if let Some(ref rww) = self.rustc_workspace_wrapper {
try_version!(Command::new(rw).args(&[rww, rustc]));
}
try_version!(Command::new(rw).arg(rustc));
}
if let Some(ref rww) = self.rustc_workspace_wrapper {
try_version!(Command::new(rww).arg(rustc));
}
Version::from_command(&mut Command::new(rustc))
}
}
fn get_rustc_wrapper(workspace: bool) -> Option<PathBuf> {
// We didn't really know whether the workspace wrapper is applicable until Cargo started
// deliberately setting or unsetting it in rust-lang/cargo#9601. We'll use the encoded
// rustflags as a proxy for that change for now, but we could instead check version 1.55.
if workspace && env::var_os("CARGO_ENCODED_RUSTFLAGS").is_none() {
return None;
}
let name = if workspace {
"RUSTC_WORKSPACE_WRAPPER"
} else {
"RUSTC_WRAPPER"
};
if let Some(wrapper) = env::var_os(name) {
// NB: `OsStr` didn't get `len` or `is_empty` until 1.9.
if wrapper != OsString::new() {
return Some(wrapper.into());
}
}
None
}

View File

@ -133,6 +133,22 @@ fn probe_constant() {
ac.assert_min(1, 39, ac.probe_constant(r#""test".len()"#)); ac.assert_min(1, 39, ac.probe_constant(r#""test".len()"#));
} }
#[test]
fn probe_raw() {
let ac = AutoCfg::for_test().unwrap();
let prefix = if ac.no_std { "#![no_std]\n" } else { "" };
let f = |s| format!("{}{}", prefix, s);
// This attribute **must** be used at the crate level.
assert!(ac.probe_raw(&f("#![no_builtins]")).is_ok());
assert!(ac.probe_raw(&f("#![deny(dead_code)] fn x() {}")).is_err());
assert!(ac.probe_raw(&f("#![allow(dead_code)] fn x() {}")).is_ok());
assert!(ac
.probe_raw(&f("#![deny(dead_code)] pub fn x() {}"))
.is_ok());
}
#[test] #[test]
fn dir_does_not_contain_target() { fn dir_does_not_contain_target() {
assert!(!super::dir_contains_target( assert!(!super::dir_contains_target(

View File

@ -1,4 +1,3 @@
use std::path::Path;
use std::process::Command; use std::process::Command;
use std::str; use std::str;
@ -22,9 +21,9 @@ impl Version {
} }
} }
pub fn from_rustc(rustc: &Path) -> Result<Self, Error> { pub fn from_command(command: &mut Command) -> Result<Self, Error> {
// Get rustc's verbose version // Get rustc's verbose version
let output = try!(Command::new(rustc) let output = try!(command
.args(&["--version", "--verbose"]) .args(&["--version", "--verbose"])
.output() .output()
.map_err(error::from_io)); .map_err(error::from_io));

12
pve-rs/vendor/autocfg/tests/wrap_ignored vendored Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
for arg in "$@"; do
case "$arg" in
# Add our own version so we can check that the wrapper is used for that.
"--version") echo "release: 12345.6789.0" ;;
# Read all input so the writer doesn't get EPIPE when we exit.
"-") read -d "" PROBE ;;
esac
done
exit 0

View File

@ -39,13 +39,18 @@ fn test_wrappers() {
assert!(ac.probe_type("usize")); assert!(ac.probe_type("usize"));
assert!(!ac.probe_type("mesize")); assert!(!ac.probe_type("mesize"));
} }
// Either way, we should have found the inner rustc version.
assert!(ac.probe_rustc_version(1, 0));
} }
} }
// Finally, make sure that `RUSTC_WRAPPER` is applied outermost // Finally, make sure that `RUSTC_WRAPPER` is applied outermost
// by using something that doesn't pass through at all. // by using something that doesn't pass through at all.
env::set_var("RUSTC_WRAPPER", "/bin/true"); env::set_var("RUSTC_WRAPPER", "./tests/wrap_ignored");
env::set_var("RUSTC_WORKSPACE_WRAPPER", "/bin/false"); env::set_var("RUSTC_WORKSPACE_WRAPPER", "/bin/false");
let ac = autocfg::AutoCfg::new().unwrap(); let ac = autocfg::AutoCfg::new().unwrap();
assert!(ac.probe_type("mesize")); // anything goes! assert!(ac.probe_type("mesize")); // anything goes!
// Make sure we also got the version from that wrapper.
assert!(ac.probe_rustc_version(12345, 6789));
} }

View File

@ -1 +1 @@
{"files":{"Cargo.lock":"499472ec5fb35e1546de201b8644bf8b86d63beb038bdbdec69208cbc0c702df","Cargo.toml":"ee9076154780f56e4fa0b5348f3e3fda28c98868d60d91fee2a61a4c4140ab6d","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"66627f6723d9c702276ae529aaf52fc2ed0fd13204ad510d0c9a2d63e6d7d68d","benches/benchmarks.rs":"029b78bb79052ec940eecfd18067b743925189202fc16015d3c4c25b05eb6d67","build.rs":"543e435aa924d7d6923e122f17a02e082bba2a4e874ae36fbfe0dcfa1aafa861","examples/backtrace.rs":"5da0c95ccebfaffbbe7b5a92b0e488017dc375cbb5b8fb2b7712dd65b2dfb2ba","examples/raw.rs":"eda88454164ce5ebdd99c9c70ea35a61d34f5aecfdb8fcb4efd4f9738d10b093","src/backtrace/dbghelp32.rs":"c225ccc1840eb85b5b972645c9de4c662507e70afbbc9a1af720bd20a0db128d","src/backtrace/dbghelp64.rs":"fb12d20ec46ce2620bbbc31aa68a9f24afd9628c8aef8728c0e517c1bed9bff2","src/backtrace/libunwind.rs":"6f8c15a8445bab64e948afdc8d216cddf1a5e2abad3a5240db27edfa75110351","src/backtrace/miri.rs":"c90348fa8c921594cc042bfd2b2b52b7efe6b7b74be9215522339042016b099e","src/backtrace/mod.rs":"fe4346e5a353aab0a40dbb46e4d2653652d8515861f089da40063f4d609b4c83","src/backtrace/noop.rs":"21943fa1f17169ecb1dfff47fc3ee4de7c5669d4abb3fb6f11f6e39845f14a24","src/capture.rs":"ef044cadeb96f18856be9481ed7e7ae57e212da37eb8a33b029a8bb563d633ec","src/dbghelp.rs":"b8c814c2cf4b87d7bf70b9ad0a3f062392d2c2e40b9e08762f334d856f62c20f","src/lib.rs":"4c77af61c4b869ad3d8f41620dceb96d4dfa5c8f77f76dcd038986f2502730cd","src/print.rs":"9d897a980e49e259a62b6d693567d99a43d36c71d69aba9aeb34c8e485fe39cd","src/print/fuchsia.rs":"eb6c02bfffc78dfbc6a30596902636bca869f36aa4a3f891d6b3739327dc9bc4","src/symbolize/dbghelp.rs":"74e56814523cd81e1dcf4b38550b35a00a3f730e6bada349679db8d5c67bc4e6","src/symbolize/gimli.rs":"acfc828c564f58fe75a6a3c8169d16c8f1ab086f0285dfc34ed894337c35b6f2","src/symbolize/gimli/coff.rs":"1a6d69aeb9c79d1acdeb054c1af050251c774d1328ef1a964d08f01c27f2bd2f","src/symbolize/gimli/elf.rs":"1f2628645fdb183f23586b40260abf8c0695a262d26e8999361965307fe32917","src/symbolize/gimli/libs_aix.rs":"bc19376a9735f99b63107fe2a389401be11427f48ddc12636aadeb8180dd1032","src/symbolize/gimli/libs_dl_iterate_phdr.rs":"2fc6a06b9bd6761646e66d247c688862d07ebb7ac44d9a894a09ef37cd246eff","src/symbolize/gimli/libs_haiku.rs":"0a0d4b37145e898f7068cadacccf362d8216e463e7026af2ce38d75ebfd74bea","src/symbolize/gimli/libs_illumos.rs":"4886675501ae3275d14bbfbff9fd9582c7f9c46a0dda2a775fb680e5267c08f7","src/symbolize/gimli/libs_libnx.rs":"8bd076a44460e89a25c2ebd287027de73de43ced2af3aef24ab7a2e21b6f2c90","src/symbolize/gimli/libs_macos.rs":"7f155b9a12ccb4914b2985c9fcaca250b8e3351164d7fbe8a3951acbd3f8cd84","src/symbolize/gimli/libs_windows.rs":"6459f8610ca1a0fd7456539ec604f5276c94b3d0d7331357eaed338e49220a02","src/symbolize/gimli/macho.rs":"3cb44a7ff72d0b8c619463c2346f2cfdc378996bb523ceb0c5ab22b1443035b6","src/symbolize/gimli/mmap_fake.rs":"9564fcf47000e70d521b31518e205c8e6ee09b7410fb1eb1e452721757ff54ba","src/symbolize/gimli/mmap_unix.rs":"7d3d7bc6e5d34e3ecb1fe8b30d36bed404b4b9cd79d3b771c91215abfabb9ad1","src/symbolize/gimli/mmap_windows.rs":"7b90a31abdb6b5e1cf60c2bf5cacc46440976aeca4a91695a20a6ba5b8f80fd1","src/symbolize/gimli/parse_running_mmaps_unix.rs":"b0bffbe15bc55920ecbeb6afe547f81a19a6e428e1a5038d33b8a5a837fe8c3b","src/symbolize/gimli/stash.rs":"e9b4c8b5849fda70c25a40be2f9a16473b601926cf96909087cfff25a8ab42b5","src/symbolize/gimli/xcoff.rs":"b3c70cdca95597375edac968d00f0db6d4f57eb14765bdee687b1b12d53b023a","src/symbolize/miri.rs":"f5201cc8a7de24ad3424d2472cb0af59cd28563d09cc0c21e998f4cee4367ade","src/symbolize/mod.rs":"b10f42bcd93d44f374911166dc20083cbb1458e4014d378dbc1da0fa7114de19","src/symbolize/noop.rs":"5d4432079b8ae2b9382945a57ae43df57bb4b7ed2e5956d4167e051a44567388","src/types.rs":"f43c94b99d57ca66a5cfe939a46016c95b2d69d82695fb52480f7a3e5b344fd9","src/windows.rs":"69f4750feb0f586a25c7d0057a281182a62cd402b3a92afe20cad1c925ac27c5","tests/accuracy/auxiliary.rs":"71d2238da401042e007ef5ee20336d6834724bae96d93c8c52d11a5a332d7d34","tests/accuracy/main.rs":"17d215192ebecbe2ab699514e7d83b1caeed069aa2de988a594633d0785a8570","tests/common/mod.rs":"733101288a48cf94d5a87a1957724deaf2650c3e4e8aa0190a4a7db62aa90d01","tests/concurrent-panics.rs":"b60279ad5c4fb9b2754807f35179cbc8fbd7acbe6e92ac6d0f416ae75db38705","tests/current-exe-mismatch.rs":"9cd0711c6d8c332adf8a45a9fef7cce191888e47bd8da60d52c5c7f727df6b98","tests/long_fn_name.rs":"12af8bcef41f2d4f9e2711cbe2a605e15ed47b571fd871f4da1fd159494d779a","tests/sgx-image-base.rs":"564d799ce613569b9d8b65ecf027e01719409fcf3d07c9179f3c7935e364bb41","tests/skip_inner_frames.rs":"073721fe85c8ba64492e4e0ca4f742d538f2d45bdda7461da24fc298aeea69ef","tests/smoke.rs":"7b834549b30df9035845b49692e6ea9b200b7e9d5ca25e54e5c516c6bd047850"},"package":"26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"} {"files":{"Cargo.lock":"f3e9673ade6061b3c3714f4cbe700ad55dc76415eee57a49a0f27b506e9c39aa","Cargo.toml":"de058aeed296a6115052eb887ab9c381f45ab7ee0dcf684de6e81dfa8f14cab7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"66627f6723d9c702276ae529aaf52fc2ed0fd13204ad510d0c9a2d63e6d7d68d","benches/benchmarks.rs":"029b78bb79052ec940eecfd18067b743925189202fc16015d3c4c25b05eb6d67","build.rs":"543e435aa924d7d6923e122f17a02e082bba2a4e874ae36fbfe0dcfa1aafa861","examples/backtrace.rs":"5da0c95ccebfaffbbe7b5a92b0e488017dc375cbb5b8fb2b7712dd65b2dfb2ba","examples/raw.rs":"eda88454164ce5ebdd99c9c70ea35a61d34f5aecfdb8fcb4efd4f9738d10b093","src/backtrace/dbghelp32.rs":"e2ff811f32672ff92ba464f641e768a290cd7d1ddccf29651164ea40c60f2dd0","src/backtrace/dbghelp64.rs":"bb19f57b881b65d2aa020b0bc30483cc448f30ca6ad329d745ae65024c56a779","src/backtrace/libunwind.rs":"2dcf3b2b5e0c9e901293d192e7746cf172b17c4e341019f0b37ee2a28e082c86","src/backtrace/miri.rs":"c90348fa8c921594cc042bfd2b2b52b7efe6b7b74be9215522339042016b099e","src/backtrace/mod.rs":"fe4346e5a353aab0a40dbb46e4d2653652d8515861f089da40063f4d609b4c83","src/backtrace/noop.rs":"21943fa1f17169ecb1dfff47fc3ee4de7c5669d4abb3fb6f11f6e39845f14a24","src/capture.rs":"d0b21a3b4d8221f4634c7c5116c0ad6a47bf1319b9b6aee2619dce564283ef75","src/dbghelp.rs":"506ede0fd839a3a86fede18ab264ef51ff10c598ade8112473c76a2c28efc975","src/lib.rs":"69c7d90448b63d621d442021f31e41cec9f42cf48ee4f75021c5fa139771aa2f","src/print.rs":"9d897a980e49e259a62b6d693567d99a43d36c71d69aba9aeb34c8e485fe39cd","src/print/fuchsia.rs":"eb6c02bfffc78dfbc6a30596902636bca869f36aa4a3f891d6b3739327dc9bc4","src/symbolize/dbghelp.rs":"787d2ebcda97c417bc2f63fdd20665839adaed30929a206d05738d31ef525eab","src/symbolize/gimli.rs":"7ca03c2fdad6a85ba05253625565515cd13fb3b0ff9e5c09592ec15fb407fef1","src/symbolize/gimli/coff.rs":"ff0675396fc63bb30822fe1b9def4da044e640e5d31452094738ff31600d6942","src/symbolize/gimli/elf.rs":"1f2628645fdb183f23586b40260abf8c0695a262d26e8999361965307fe32917","src/symbolize/gimli/libs_aix.rs":"bc19376a9735f99b63107fe2a389401be11427f48ddc12636aadeb8180dd1032","src/symbolize/gimli/libs_dl_iterate_phdr.rs":"2fc6a06b9bd6761646e66d247c688862d07ebb7ac44d9a894a09ef37cd246eff","src/symbolize/gimli/libs_haiku.rs":"0a0d4b37145e898f7068cadacccf362d8216e463e7026af2ce38d75ebfd74bea","src/symbolize/gimli/libs_illumos.rs":"4886675501ae3275d14bbfbff9fd9582c7f9c46a0dda2a775fb680e5267c08f7","src/symbolize/gimli/libs_libnx.rs":"8bd076a44460e89a25c2ebd287027de73de43ced2af3aef24ab7a2e21b6f2c90","src/symbolize/gimli/libs_macos.rs":"7f155b9a12ccb4914b2985c9fcaca250b8e3351164d7fbe8a3951acbd3f8cd84","src/symbolize/gimli/libs_windows.rs":"6459f8610ca1a0fd7456539ec604f5276c94b3d0d7331357eaed338e49220a02","src/symbolize/gimli/macho.rs":"d75cb9c2a3640031d5269425ec4fcc4f21f364d4406cac50ef6c5eb9a718fc2d","src/symbolize/gimli/mmap_fake.rs":"9564fcf47000e70d521b31518e205c8e6ee09b7410fb1eb1e452721757ff54ba","src/symbolize/gimli/mmap_unix.rs":"7d3d7bc6e5d34e3ecb1fe8b30d36bed404b4b9cd79d3b771c91215abfabb9ad1","src/symbolize/gimli/mmap_windows.rs":"7b90a31abdb6b5e1cf60c2bf5cacc46440976aeca4a91695a20a6ba5b8f80fd1","src/symbolize/gimli/parse_running_mmaps_unix.rs":"b0bffbe15bc55920ecbeb6afe547f81a19a6e428e1a5038d33b8a5a837fe8c3b","src/symbolize/gimli/stash.rs":"e9b4c8b5849fda70c25a40be2f9a16473b601926cf96909087cfff25a8ab42b5","src/symbolize/gimli/xcoff.rs":"b3c70cdca95597375edac968d00f0db6d4f57eb14765bdee687b1b12d53b023a","src/symbolize/miri.rs":"f5201cc8a7de24ad3424d2472cb0af59cd28563d09cc0c21e998f4cee4367ade","src/symbolize/mod.rs":"e20189e4e6c453bff4fa8fbea99d96eb9e05d524deef656dd2ac9a148b87d885","src/symbolize/noop.rs":"5d4432079b8ae2b9382945a57ae43df57bb4b7ed2e5956d4167e051a44567388","src/types.rs":"f43c94b99d57ca66a5cfe939a46016c95b2d69d82695fb52480f7a3e5b344fd9","src/windows.rs":"c0eef986a3d733747d1e0ad12850efd022430c04131b4114b69100de380ad400","tests/accuracy/auxiliary.rs":"71d2238da401042e007ef5ee20336d6834724bae96d93c8c52d11a5a332d7d34","tests/accuracy/main.rs":"851778c046bc5b51f91777716ffe9896e0f872197d069e2dcd9a8b5ef4c98b01","tests/common/mod.rs":"733101288a48cf94d5a87a1957724deaf2650c3e4e8aa0190a4a7db62aa90d01","tests/concurrent-panics.rs":"b60279ad5c4fb9b2754807f35179cbc8fbd7acbe6e92ac6d0f416ae75db38705","tests/current-exe-mismatch.rs":"9cd0711c6d8c332adf8a45a9fef7cce191888e47bd8da60d52c5c7f727df6b98","tests/long_fn_name.rs":"12af8bcef41f2d4f9e2711cbe2a605e15ed47b571fd871f4da1fd159494d779a","tests/sgx-image-base.rs":"564d799ce613569b9d8b65ecf027e01719409fcf3d07c9179f3c7935e364bb41","tests/skip_inner_frames.rs":"073721fe85c8ba64492e4e0ca4f742d538f2d45bdda7461da24fc298aeea69ef","tests/smoke.rs":"ad0a1894fc4922f03fe01b61e5fc563d2c9fd50a46b25faafc42c11966a791d6"},"package":"5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"}

29
pve-rs/vendor/backtrace/Cargo.lock generated vendored
View File

@ -4,9 +4,9 @@ version = 3
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.21.0" version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
dependencies = [ dependencies = [
"gimli", "gimli",
] ]
@ -19,7 +19,7 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.71" version = "0.3.73"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cc", "cc",
@ -30,16 +30,15 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
"object", "object",
"rustc-demangle", "rustc-demangle",
"rustc-serialize",
"serde", "serde",
"winapi", "winapi",
] ]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.90" version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -58,9 +57,9 @@ dependencies = [
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.28.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]] [[package]]
name = "libc" name = "libc"
@ -95,9 +94,9 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.32.0" version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -122,15 +121,9 @@ dependencies = [
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.23" version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-serialize"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401"
[[package]] [[package]]
name = "serde" name = "serde"

View File

@ -13,12 +13,14 @@
edition = "2021" edition = "2021"
rust-version = "1.65.0" rust-version = "1.65.0"
name = "backtrace" name = "backtrace"
version = "0.3.71" version = "0.3.73"
authors = ["The Rust Project Developers"] authors = ["The Rust Project Developers"]
build = "build.rs" build = "build.rs"
exclude = ["/ci/"] exclude = ["/ci/"]
autoexamples = true autobins = false
autotests = true autoexamples = false
autotests = false
autobenches = false
description = """ description = """
A library to acquire a stack trace (backtrace) at runtime in a Rust program. A library to acquire a stack trace (backtrace) at runtime in a Rust program.
""" """
@ -28,42 +30,62 @@ readme = "README.md"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/backtrace-rs" repository = "https://github.com/rust-lang/backtrace-rs"
[lib]
name = "backtrace"
path = "src/lib.rs"
[[example]] [[example]]
name = "backtrace" name = "backtrace"
path = "examples/backtrace.rs"
required-features = ["std"] required-features = ["std"]
[[example]] [[example]]
name = "raw" name = "raw"
path = "examples/raw.rs"
required-features = ["std"] required-features = ["std"]
[[test]] [[test]]
name = "skip_inner_frames" name = "skip_inner_frames"
path = "tests/skip_inner_frames.rs"
required-features = ["std"] required-features = ["std"]
[[test]] [[test]]
name = "long_fn_name" name = "long_fn_name"
path = "tests/long_fn_name.rs"
required-features = ["std"] required-features = ["std"]
[[test]] [[test]]
name = "smoke" name = "smoke"
path = "tests/smoke.rs"
required-features = ["std"] required-features = ["std"]
edition = "2021" edition = "2021"
[[test]] [[test]]
name = "accuracy" name = "accuracy"
path = "tests/accuracy/main.rs"
required-features = ["std"] required-features = ["std"]
edition = "2021" edition = "2021"
[[test]] [[test]]
name = "concurrent-panics" name = "concurrent-panics"
path = "tests/concurrent-panics.rs"
harness = false harness = false
required-features = ["std"] required-features = ["std"]
[[test]] [[test]]
name = "current-exe-mismatch" name = "current-exe-mismatch"
path = "tests/current-exe-mismatch.rs"
harness = false harness = false
required-features = ["std"] required-features = ["std"]
[[test]]
name = "sgx-image-base"
path = "tests/sgx-image-base.rs"
[[bench]]
name = "benchmarks"
path = "benches/benchmarks.rs"
[dependencies.cfg-if] [dependencies.cfg-if]
version = "1.0" version = "1.0"
@ -74,11 +96,7 @@ optional = true
default-features = false default-features = false
[dependencies.rustc-demangle] [dependencies.rustc-demangle]
version = "0.1.4" version = "0.1.24"
[dependencies.rustc-serialize]
version = "0.3"
optional = true
[dependencies.serde] [dependencies.serde]
version = "1.0" version = "1.0"
@ -89,18 +107,16 @@ optional = true
version = "0.7" version = "0.7"
[build-dependencies.cc] [build-dependencies.cc]
version = "1.0.90" version = "1.0.97"
[features] [features]
coresymbolication = [] coresymbolication = []
dbghelp = [] dbghelp = []
default = ["std"] default = ["std"]
dl_iterate_phdr = []
dladdr = [] dladdr = []
gimli-symbolize = []
kernel32 = [] kernel32 = []
libbacktrace = []
libunwind = [] libunwind = []
serialize-rustc = ["rustc-serialize"]
serialize-serde = ["serde"] serialize-serde = ["serde"]
std = [] std = []
unix-backtrace = [] unix-backtrace = []
@ -115,10 +131,12 @@ verify-winapi = [
"winapi/tlhelp32", "winapi/tlhelp32",
"winapi/winbase", "winapi/winbase",
"winapi/winnt", "winapi/winnt",
"winapi/winnls",
"winapi/stringapiset",
] ]
[target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.addr2line] [target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.addr2line]
version = "0.21.0" version = "0.22.0"
default-features = false default-features = false
[target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.libc] [target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.libc]
@ -130,7 +148,7 @@ version = "0.7.0"
default-features = false default-features = false
[target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.object] [target."cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))".dependencies.object]
version = "0.32.0" version = "0.36.0"
features = [ features = [
"read_core", "read_core",
"elf", "elf",
@ -145,3 +163,6 @@ default-features = false
[target."cfg(windows)".dependencies.winapi] [target."cfg(windows)".dependencies.winapi]
version = "0.3.9" version = "0.3.9"
optional = true optional = true
[lints.rust]
unexpected_cfgs = "allow"

View File

@ -1,6 +1,6 @@
//! Backtrace strategy for MSVC platforms. //! Backtrace strategy for Windows platforms.
//! //!
//! This module contains the ability to generate a backtrace on MSVC using one //! This module contains the ability to generate a backtrace on Windows using one
//! of two possible methods. The `StackWalkEx` function is primarily used if //! of two possible methods. The `StackWalkEx` function is primarily used if
//! possible, but not all systems have that. Failing that the `StackWalk64` //! possible, but not all systems have that. Failing that the `StackWalk64`
//! function is used instead. Note that `StackWalkEx` is favored because it //! function is used instead. Note that `StackWalkEx` is favored because it

View File

@ -1,19 +1,10 @@
//! Backtrace strategy for MSVC platforms. //! Backtrace strategy for Windows `x86_64` and `aarch64` platforms.
//! //!
//! This module contains the ability to capture a backtrace on MSVC using one //! This module contains the ability to capture a backtrace on Windows using
//! of three possible methods. For `x86_64` and `aarch64`, we use `RtlVirtualUnwind` //! `RtlVirtualUnwind` to walk the stack one frame at a time. This function is much faster than using
//! to walk the stack one frame at a time. This function is much faster than using
//! `dbghelp!StackWalk*` because it does not load debug info to report inlined frames. //! `dbghelp!StackWalk*` because it does not load debug info to report inlined frames.
//! We still report inlined frames during symbolization by consulting the appropriate //! We still report inlined frames during symbolization by consulting the appropriate
//! `dbghelp` functions. //! `dbghelp` functions.
//!
//! For all other platforms, primarily `i686`, the `StackWalkEx` function is used if
//! possible, but not all systems have that. Failing that the `StackWalk64` function
//! is used instead. Note that `StackWalkEx` is favored because it handles debuginfo
//! internally and returns inline frame information.
//!
//! Note that all dbghelp support is loaded dynamically, see `src/dbghelp.rs`
//! for more information about that.
#![allow(bad_style)] #![allow(bad_style)]
@ -95,44 +86,66 @@ impl MyContext {
pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) { pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
use core::ptr; use core::ptr;
// Capture the initial context to start walking from.
let mut context = core::mem::zeroed::<MyContext>(); let mut context = core::mem::zeroed::<MyContext>();
RtlCaptureContext(&mut context.0); RtlCaptureContext(&mut context.0);
// Call `RtlVirtualUnwind` to find the previous stack frame, walking until we hit ip = 0. loop {
while context.ip() != 0 { let ip = context.ip();
let mut base = 0;
let fn_entry = RtlLookupFunctionEntry(context.ip(), &mut base, ptr::null_mut()); // The base address of the module containing the function will be stored here
// when RtlLookupFunctionEntry returns successfully.
let mut base = 0;
let fn_entry = RtlLookupFunctionEntry(ip, &mut base, ptr::null_mut());
if fn_entry.is_null() { if fn_entry.is_null() {
// No function entry could be found - this may indicate a corrupt
// stack or that a binary was unloaded (amongst other issues). Stop
// walking and don't call the callback as we can't be confident in
// this frame or the rest of the stack.
break; break;
} }
let frame = super::Frame { let frame = super::Frame {
inner: Frame { inner: Frame {
base_address: fn_entry.cast::<c_void>(), base_address: base as *mut c_void,
ip: context.ip() as *mut c_void, ip: ip as *mut c_void,
sp: context.sp() as *mut c_void, sp: context.sp() as *mut c_void,
#[cfg(not(target_env = "gnu"))] #[cfg(not(target_env = "gnu"))]
inline_context: None, inline_context: None,
}, },
}; };
// We've loaded all the info about the current frame, so now call the
// callback.
if !cb(&frame) { if !cb(&frame) {
// Callback told us to stop, so we're done.
break; break;
} }
// Unwind to the next frame.
let previous_ip = ip;
let previous_sp = context.sp();
let mut handler_data = 0usize; let mut handler_data = 0usize;
let mut establisher_frame = 0; let mut establisher_frame = 0;
RtlVirtualUnwind( RtlVirtualUnwind(
0, 0,
base, base,
context.ip(), ip,
fn_entry, fn_entry,
&mut context.0, &mut context.0,
ptr::addr_of_mut!(handler_data).cast::<PVOID>(), ptr::addr_of_mut!(handler_data).cast::<PVOID>(),
&mut establisher_frame, &mut establisher_frame,
ptr::null_mut(), ptr::null_mut(),
); );
// RtlVirtualUnwind indicates the end of the stack in two different ways:
// * On x64, it sets the instruction pointer to 0.
// * On ARM64, it leaves the context unchanged (easiest way to check is
// to see if the instruction and stack pointers are the same).
// If we detect either of these, then unwinding is completed.
let ip = context.ip();
if ip == 0 || (ip == previous_ip && context.sp() == previous_sp) {
break;
}
} }
} }

View File

@ -15,7 +15,6 @@
//! //!
//! This is the default unwinding API for all non-Windows platforms currently. //! This is the default unwinding API for all non-Windows platforms currently.
use super::super::Bomb;
use core::ffi::c_void; use core::ffi::c_void;
use core::ptr::addr_of_mut; use core::ptr::addr_of_mut;
@ -100,6 +99,18 @@ impl Clone for Frame {
} }
} }
struct Bomb {
enabled: bool,
}
impl Drop for Bomb {
fn drop(&mut self) {
if self.enabled {
panic!("cannot panic during the backtrace function");
}
}
}
#[inline(always)] #[inline(always)]
pub unsafe fn trace(mut cb: &mut dyn FnMut(&super::Frame) -> bool) { pub unsafe fn trace(mut cb: &mut dyn FnMut(&super::Frame) -> bool) {
uw::_Unwind_Backtrace(trace_fn, addr_of_mut!(cb).cast()); uw::_Unwind_Backtrace(trace_fn, addr_of_mut!(cb).cast());

View File

@ -1,5 +1,7 @@
#[cfg(feature = "serde")]
use crate::resolve;
use crate::PrintFmt; use crate::PrintFmt;
use crate::{resolve, resolve_frame, trace, BacktraceFmt, Symbol, SymbolName}; use crate::{resolve_frame, trace, BacktraceFmt, Symbol, SymbolName};
use std::ffi::c_void; use std::ffi::c_void;
use std::fmt; use std::fmt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -21,7 +23,6 @@ use serde::{Deserialize, Serialize};
/// This function requires the `std` feature of the `backtrace` crate to be /// This function requires the `std` feature of the `backtrace` crate to be
/// enabled, and the `std` feature is enabled by default. /// enabled, and the `std` feature is enabled by default.
#[derive(Clone)] #[derive(Clone)]
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct Backtrace { pub struct Backtrace {
// Frames here are listed from top-to-bottom of the stack // Frames here are listed from top-to-bottom of the stack
@ -51,7 +52,7 @@ pub struct BacktraceFrame {
#[derive(Clone)] #[derive(Clone)]
enum Frame { enum Frame {
Raw(crate::Frame), Raw(crate::Frame),
#[allow(dead_code)] #[cfg(feature = "serde")]
Deserialized { Deserialized {
ip: usize, ip: usize,
symbol_address: usize, symbol_address: usize,
@ -63,6 +64,7 @@ impl Frame {
fn ip(&self) -> *mut c_void { fn ip(&self) -> *mut c_void {
match *self { match *self {
Frame::Raw(ref f) => f.ip(), Frame::Raw(ref f) => f.ip(),
#[cfg(feature = "serde")]
Frame::Deserialized { ip, .. } => ip as *mut c_void, Frame::Deserialized { ip, .. } => ip as *mut c_void,
} }
} }
@ -70,6 +72,7 @@ impl Frame {
fn symbol_address(&self) -> *mut c_void { fn symbol_address(&self) -> *mut c_void {
match *self { match *self {
Frame::Raw(ref f) => f.symbol_address(), Frame::Raw(ref f) => f.symbol_address(),
#[cfg(feature = "serde")]
Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void, Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void,
} }
} }
@ -77,6 +80,7 @@ impl Frame {
fn module_base_address(&self) -> Option<*mut c_void> { fn module_base_address(&self) -> Option<*mut c_void> {
match *self { match *self {
Frame::Raw(ref f) => f.module_base_address(), Frame::Raw(ref f) => f.module_base_address(),
#[cfg(feature = "serde")]
Frame::Deserialized { Frame::Deserialized {
module_base_address, module_base_address,
.. ..
@ -98,6 +102,7 @@ impl Frame {
}; };
match *self { match *self {
Frame::Raw(ref f) => resolve_frame(f, sym), Frame::Raw(ref f) => resolve_frame(f, sym),
#[cfg(feature = "serde")]
Frame::Deserialized { ip, .. } => { Frame::Deserialized { ip, .. } => {
resolve(ip as *mut c_void, sym); resolve(ip as *mut c_void, sym);
} }
@ -116,7 +121,6 @@ impl Frame {
/// This function requires the `std` feature of the `backtrace` crate to be /// This function requires the `std` feature of the `backtrace` crate to be
/// enabled, and the `std` feature is enabled by default. /// enabled, and the `std` feature is enabled by default.
#[derive(Clone)] #[derive(Clone)]
#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct BacktraceSymbol { pub struct BacktraceSymbol {
name: Option<Vec<u8>>, name: Option<Vec<u8>>,
@ -440,53 +444,6 @@ impl fmt::Debug for BacktraceSymbol {
} }
} }
#[cfg(feature = "serialize-rustc")]
mod rustc_serialize_impls {
use super::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
#[derive(RustcEncodable, RustcDecodable)]
struct SerializedFrame {
ip: usize,
symbol_address: usize,
module_base_address: Option<usize>,
symbols: Option<Vec<BacktraceSymbol>>,
}
impl Decodable for BacktraceFrame {
fn decode<D>(d: &mut D) -> Result<Self, D::Error>
where
D: Decoder,
{
let frame: SerializedFrame = SerializedFrame::decode(d)?;
Ok(BacktraceFrame {
frame: Frame::Deserialized {
ip: frame.ip,
symbol_address: frame.symbol_address,
module_base_address: frame.module_base_address,
},
symbols: frame.symbols,
})
}
}
impl Encodable for BacktraceFrame {
fn encode<E>(&self, e: &mut E) -> Result<(), E::Error>
where
E: Encoder,
{
let BacktraceFrame { frame, symbols } = self;
SerializedFrame {
ip: frame.ip() as usize,
symbol_address: frame.symbol_address() as usize,
module_base_address: frame.module_base_address().map(|addr| addr as usize),
symbols: symbols.clone(),
}
.encode(e)
}
}
}
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
mod serde_impls { mod serde_impls {
use super::*; use super::*;

View File

@ -376,16 +376,21 @@ pub fn init() -> Result<Init, ()> {
DBGHELP.ensure_open()?; DBGHELP.ensure_open()?;
static mut INITIALIZED: bool = false; static mut INITIALIZED: bool = false;
if INITIALIZED { if !INITIALIZED {
return Ok(ret); set_optional_options();
INITIALIZED = true;
} }
Ok(ret)
let orig = DBGHELP.SymGetOptions().unwrap()(); }
}
fn set_optional_options() -> Option<()> {
unsafe {
let orig = DBGHELP.SymGetOptions()?();
// Ensure that the `SYMOPT_DEFERRED_LOADS` flag is set, because // Ensure that the `SYMOPT_DEFERRED_LOADS` flag is set, because
// according to MSVC's own docs about this: "This is the fastest, most // according to MSVC's own docs about this: "This is the fastest, most
// efficient way to use the symbol handler.", so let's do that! // efficient way to use the symbol handler.", so let's do that!
DBGHELP.SymSetOptions().unwrap()(orig | SYMOPT_DEFERRED_LOADS); DBGHELP.SymSetOptions()?(orig | SYMOPT_DEFERRED_LOADS);
// Actually initialize symbols with MSVC. Note that this can fail, but we // Actually initialize symbols with MSVC. Note that this can fail, but we
// ignore it. There's not a ton of prior art for this per se, but LLVM // ignore it. There's not a ton of prior art for this per se, but LLVM
@ -399,7 +404,7 @@ pub fn init() -> Result<Init, ()> {
// the time, but now that it's using this crate it means that someone will // the time, but now that it's using this crate it means that someone will
// get to initialization first and the other will pick up that // get to initialization first and the other will pick up that
// initialization. // initialization.
DBGHELP.SymInitializeW().unwrap()(GetCurrentProcess(), ptr::null_mut(), TRUE); DBGHELP.SymInitializeW()?(GetCurrentProcess(), ptr::null_mut(), TRUE);
// The default search path for dbghelp will only look in the current working // The default search path for dbghelp will only look in the current working
// directory and (possibly) `_NT_SYMBOL_PATH` and `_NT_ALT_SYMBOL_PATH`. // directory and (possibly) `_NT_SYMBOL_PATH` and `_NT_ALT_SYMBOL_PATH`.
@ -413,7 +418,7 @@ pub fn init() -> Result<Init, ()> {
search_path_buf.resize(1024, 0); search_path_buf.resize(1024, 0);
// Prefill the buffer with the current search path. // Prefill the buffer with the current search path.
if DBGHELP.SymGetSearchPathW().unwrap()( if DBGHELP.SymGetSearchPathW()?(
GetCurrentProcess(), GetCurrentProcess(),
search_path_buf.as_mut_ptr(), search_path_buf.as_mut_ptr(),
search_path_buf.len() as _, search_path_buf.len() as _,
@ -433,7 +438,7 @@ pub fn init() -> Result<Init, ()> {
let mut search_path = SearchPath::new(search_path_buf); let mut search_path = SearchPath::new(search_path_buf);
// Update the search path to include the directory of the executable and each DLL. // Update the search path to include the directory of the executable and each DLL.
DBGHELP.EnumerateLoadedModulesW64().unwrap()( DBGHELP.EnumerateLoadedModulesW64()?(
GetCurrentProcess(), GetCurrentProcess(),
Some(enum_loaded_modules_callback), Some(enum_loaded_modules_callback),
((&mut search_path) as *mut SearchPath) as *mut c_void, ((&mut search_path) as *mut SearchPath) as *mut c_void,
@ -442,11 +447,9 @@ pub fn init() -> Result<Init, ()> {
let new_search_path = search_path.finalize(); let new_search_path = search_path.finalize();
// Set the new search path. // Set the new search path.
DBGHELP.SymSetSearchPathW().unwrap()(GetCurrentProcess(), new_search_path.as_ptr()); DBGHELP.SymSetSearchPathW()?(GetCurrentProcess(), new_search_path.as_ptr());
INITIALIZED = true;
Ok(ret)
} }
Some(())
} }
struct SearchPath { struct SearchPath {

View File

@ -97,8 +97,6 @@
// irrelevant as this crate is developed out-of-tree. // irrelevant as this crate is developed out-of-tree.
#![cfg_attr(backtrace_in_libstd, allow(warnings))] #![cfg_attr(backtrace_in_libstd, allow(warnings))]
#![cfg_attr(not(feature = "std"), allow(dead_code))] #![cfg_attr(not(feature = "std"), allow(dead_code))]
// We know this is deprecated, it's only here for back-compat reasons.
#![cfg_attr(feature = "rustc-serialize", allow(deprecated))]
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[macro_use] #[macro_use]
@ -140,21 +138,6 @@ cfg_if::cfg_if! {
} }
} }
#[allow(dead_code)]
struct Bomb {
enabled: bool,
}
#[allow(dead_code)]
impl Drop for Bomb {
fn drop(&mut self) {
if self.enabled {
panic!("cannot panic during the backtrace function");
}
}
}
#[allow(dead_code)]
#[cfg(feature = "std")] #[cfg(feature = "std")]
mod lock { mod lock {
use std::boxed::Box; use std::boxed::Box;
@ -162,32 +145,95 @@ mod lock {
use std::ptr; use std::ptr;
use std::sync::{Mutex, MutexGuard, Once}; use std::sync::{Mutex, MutexGuard, Once};
/// A "Maybe" LockGuard
pub struct LockGuard(Option<MutexGuard<'static, ()>>); pub struct LockGuard(Option<MutexGuard<'static, ()>>);
/// The global lock, lazily allocated on first use
static mut LOCK: *mut Mutex<()> = ptr::null_mut(); static mut LOCK: *mut Mutex<()> = ptr::null_mut();
static INIT: Once = Once::new(); static INIT: Once = Once::new();
// Whether this thread is the one that holds the lock
thread_local!(static LOCK_HELD: Cell<bool> = Cell::new(false)); thread_local!(static LOCK_HELD: Cell<bool> = Cell::new(false));
impl Drop for LockGuard { impl Drop for LockGuard {
fn drop(&mut self) { fn drop(&mut self) {
// Don't do anything if we're a LockGuard(None)
if self.0.is_some() { if self.0.is_some() {
LOCK_HELD.with(|slot| { LOCK_HELD.with(|slot| {
// Immediately crash if we somehow aren't the thread holding this lock
assert!(slot.get()); assert!(slot.get());
// We are no longer the thread holding this lock
slot.set(false); slot.set(false);
}); });
} }
// lock implicitly released here, if we're a LockGuard(Some(..))
} }
} }
/// Acquire a partially unsound(!!!) global re-entrant lock over
/// backtrace's internals.
///
/// That is, this lock can be acquired as many times as you want
/// on a single thread without deadlocking, allowing one thread
/// to acquire exclusive access to the ability to make backtraces.
/// Calls to this locking function are freely sprinkled in every place
/// where that needs to be enforced.
///
///
/// # Why
///
/// This was first introduced to guard uses of Windows' dbghelp API,
/// which isn't threadsafe. It's unclear if other things now rely on
/// this locking.
///
///
/// # How
///
/// The basic idea is to have a single global mutex, and a thread_local
/// boolean saying "yep this is the thread that acquired the mutex".
///
/// The first time a thread acquires the lock, it is handed a
/// `LockGuard(Some(..))` that will actually release the lock on Drop.
/// All subsequence attempts to lock on the same thread will see
/// that their thread acquired the lock, and get `LockGuard(None)`
/// which will do nothing when dropped.
///
///
/// # Safety
///
/// As long as you only ever assign the returned LockGuard to a freshly
/// declared local variable, it will do its job correctly, as the "first"
/// LockGuard will strictly outlive all subsequent LockGuards and
/// properly release the lock when the thread is done with backtracing.
///
/// However if you ever attempt to store a LockGuard beyond the scope
/// it was acquired in, it might actually be a `LockGuard(None)` that
/// doesn't actually hold the lock! In this case another thread might
/// acquire the lock and you'll get races this system was intended to
/// avoid!
///
/// This is why this is "partially unsound". As a public API this would
/// be unacceptable, but this is crate-private, and if you use this in
/// the most obvious and simplistic way it Just Works™.
///
/// Note however that std specifically bypasses this lock, and uses
/// the `*_unsynchronized` backtrace APIs. This is "fine" because
/// it wraps its own calls to backtrace in a non-reentrant Mutex
/// that prevents two backtraces from getting interleaved during printing.
pub fn lock() -> LockGuard { pub fn lock() -> LockGuard {
// If we're the thread holding this lock, pretend to acquire the lock
// again by returning a LockGuard(None)
if LOCK_HELD.with(|l| l.get()) { if LOCK_HELD.with(|l| l.get()) {
return LockGuard(None); return LockGuard(None);
} }
// Insist that we totally are the thread holding the lock
// (our thread will block until we are)
LOCK_HELD.with(|s| s.set(true)); LOCK_HELD.with(|s| s.set(true));
unsafe { unsafe {
// lazily allocate the lock if necessary
INIT.call_once(|| { INIT.call_once(|| {
LOCK = Box::into_raw(Box::new(Mutex::new(()))); LOCK = Box::into_raw(Box::new(Mutex::new(())));
}); });
// ok *actually* try to acquire the lock, blocking as necessary
LockGuard(Some((*LOCK).lock().unwrap())) LockGuard(Some((*LOCK).lock().unwrap()))
} }
} }

View File

@ -19,7 +19,6 @@
use super::super::{dbghelp, windows::*}; use super::super::{dbghelp, windows::*};
use super::{BytesOrWideString, ResolveWhat, SymbolName}; use super::{BytesOrWideString, ResolveWhat, SymbolName};
use core::char;
use core::ffi::c_void; use core::ffi::c_void;
use core::marker; use core::marker;
use core::mem; use core::mem;
@ -91,7 +90,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
ResolveWhat::Frame(frame) => { ResolveWhat::Frame(frame) => {
resolve_with_inline(&dbghelp, frame.ip(), frame.inner.inline_context(), cb) resolve_with_inline(&dbghelp, frame.ip(), frame.inner.inline_context(), cb)
} }
} };
} }
#[cfg(target_vendor = "win7")] #[cfg(target_vendor = "win7")]
@ -116,7 +115,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
ResolveWhat::Frame(frame) => { ResolveWhat::Frame(frame) => {
resolve_inner(&dbghelp, frame.ip(), frame.inner.inline_context(), cb) resolve_inner(&dbghelp, frame.ip(), frame.inner.inline_context(), cb)
} }
} };
} }
/// Resolve the address using the legacy dbghelp API. /// Resolve the address using the legacy dbghelp API.
@ -129,13 +128,14 @@ unsafe fn resolve_legacy(
addr: *mut c_void, addr: *mut c_void,
_inline_context: Option<DWORD>, _inline_context: Option<DWORD>,
cb: &mut dyn FnMut(&super::Symbol), cb: &mut dyn FnMut(&super::Symbol),
) { ) -> Option<()> {
let addr = super::adjust_ip(addr) as DWORD64; let addr = super::adjust_ip(addr) as DWORD64;
do_resolve( do_resolve(
|info| dbghelp.SymFromAddrW()(GetCurrentProcess(), addr, &mut 0, info), |info| dbghelp.SymFromAddrW()(GetCurrentProcess(), addr, &mut 0, info),
|line| dbghelp.SymGetLineFromAddrW64()(GetCurrentProcess(), addr, &mut 0, line), |line| dbghelp.SymGetLineFromAddrW64()(GetCurrentProcess(), addr, &mut 0, line),
cb, cb,
) );
Some(())
} }
/// Resolve the address using the modern dbghelp APIs. /// Resolve the address using the modern dbghelp APIs.
@ -147,22 +147,28 @@ unsafe fn resolve_with_inline(
addr: *mut c_void, addr: *mut c_void,
inline_context: Option<DWORD>, inline_context: Option<DWORD>,
cb: &mut dyn FnMut(&super::Symbol), cb: &mut dyn FnMut(&super::Symbol),
) { ) -> Option<()> {
let current_process = GetCurrentProcess(); let current_process = GetCurrentProcess();
// Ensure we have the functions we need. Return if any aren't found.
let SymFromInlineContextW = (*dbghelp.dbghelp()).SymFromInlineContextW()?;
let SymGetLineFromInlineContextW = (*dbghelp.dbghelp()).SymGetLineFromInlineContextW()?;
let addr = super::adjust_ip(addr) as DWORD64; let addr = super::adjust_ip(addr) as DWORD64;
let (inlined_frame_count, inline_context) = if let Some(ic) = inline_context { let (inlined_frame_count, inline_context) = if let Some(ic) = inline_context {
(0, ic) (0, ic)
} else { } else {
let mut inlined_frame_count = dbghelp.SymAddrIncludeInlineTrace()(current_process, addr); let SymAddrIncludeInlineTrace = (*dbghelp.dbghelp()).SymAddrIncludeInlineTrace()?;
let SymQueryInlineTrace = (*dbghelp.dbghelp()).SymQueryInlineTrace()?;
let mut inlined_frame_count = SymAddrIncludeInlineTrace(current_process, addr);
let mut inline_context = 0; let mut inline_context = 0;
// If there is are inlined frames but we can't load them for some reason OR if there are no // If there is are inlined frames but we can't load them for some reason OR if there are no
// inlined frames, then we disregard inlined_frame_count and inline_context. // inlined frames, then we disregard inlined_frame_count and inline_context.
if (inlined_frame_count > 0 if (inlined_frame_count > 0
&& dbghelp.SymQueryInlineTrace()( && SymQueryInlineTrace(
current_process, current_process,
addr, addr,
0, 0,
@ -184,22 +190,14 @@ unsafe fn resolve_with_inline(
for inline_context in inline_context..last_inline_context { for inline_context in inline_context..last_inline_context {
do_resolve( do_resolve(
|info| { |info| SymFromInlineContextW(current_process, addr, inline_context, &mut 0, info),
dbghelp.SymFromInlineContextW()(current_process, addr, inline_context, &mut 0, info)
},
|line| { |line| {
dbghelp.SymGetLineFromInlineContextW()( SymGetLineFromInlineContextW(current_process, addr, inline_context, 0, &mut 0, line)
current_process,
addr,
inline_context,
0,
&mut 0,
line,
)
}, },
cb, cb,
); );
} }
Some(())
} }
unsafe fn do_resolve( unsafe fn do_resolve(
@ -225,26 +223,27 @@ unsafe fn do_resolve(
// the real value. // the real value.
let name_len = ::core::cmp::min(info.NameLen as usize, info.MaxNameLen as usize - 1); let name_len = ::core::cmp::min(info.NameLen as usize, info.MaxNameLen as usize - 1);
let name_ptr = info.Name.as_ptr().cast::<u16>(); let name_ptr = info.Name.as_ptr().cast::<u16>();
let name = slice::from_raw_parts(name_ptr, name_len);
// Reencode the utf-16 symbol to utf-8 so we can use `SymbolName::new` like // Reencode the utf-16 symbol to utf-8 so we can use `SymbolName::new` like
// all other platforms // all other platforms
let mut name_len = 0; let mut name_buffer = [0_u8; 256];
let mut name_buffer = [0; 256]; let mut name_len = WideCharToMultiByte(
{ CP_UTF8,
let mut remaining = &mut name_buffer[..]; 0,
for c in char::decode_utf16(name.iter().cloned()) { name_ptr,
let c = c.unwrap_or(char::REPLACEMENT_CHARACTER); name_len as i32,
let len = c.len_utf8(); name_buffer.as_mut_ptr().cast::<i8>(),
if len < remaining.len() { name_buffer.len() as i32,
c.encode_utf8(remaining); core::ptr::null_mut(),
let tmp = remaining; core::ptr::null_mut(),
remaining = &mut tmp[len..]; ) as usize;
name_len += len; if name_len == 0 {
} else { // If the returned length is zero that means the buffer wasn't big enough.
break; // However, the buffer will be filled with as much as will fit.
} name_len = name_buffer.len();
} } else if name_len > name_buffer.len() {
// This can't happen.
return;
} }
let name = ptr::addr_of!(name_buffer[..name_len]); let name = ptr::addr_of!(name_buffer[..name_len]);

View File

@ -30,15 +30,16 @@ cfg_if::cfg_if! {
if #[cfg(windows)] { if #[cfg(windows)] {
#[path = "gimli/mmap_windows.rs"] #[path = "gimli/mmap_windows.rs"]
mod mmap; mod mmap;
} else if #[cfg(target_vendor = "apple")] {
#[path = "gimli/mmap_unix.rs"]
mod mmap;
} else if #[cfg(any( } else if #[cfg(any(
target_os = "android", target_os = "android",
target_os = "freebsd", target_os = "freebsd",
target_os = "fuchsia", target_os = "fuchsia",
target_os = "haiku", target_os = "haiku",
target_os = "hurd", target_os = "hurd",
target_os = "ios",
target_os = "linux", target_os = "linux",
target_os = "macos",
target_os = "openbsd", target_os = "openbsd",
target_os = "solaris", target_os = "solaris",
target_os = "illumos", target_os = "illumos",
@ -195,12 +196,7 @@ cfg_if::cfg_if! {
if #[cfg(windows)] { if #[cfg(windows)] {
mod coff; mod coff;
use self::coff::{handle_split_dwarf, Object}; use self::coff::{handle_split_dwarf, Object};
} else if #[cfg(any( } else if #[cfg(any(target_vendor = "apple"))] {
target_os = "macos",
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
))] {
mod macho; mod macho;
use self::macho::{handle_split_dwarf, Object}; use self::macho::{handle_split_dwarf, Object};
} else if #[cfg(target_os = "aix")] { } else if #[cfg(target_os = "aix")] {
@ -216,12 +212,7 @@ cfg_if::cfg_if! {
if #[cfg(windows)] { if #[cfg(windows)] {
mod libs_windows; mod libs_windows;
use libs_windows::native_libraries; use libs_windows::native_libraries;
} else if #[cfg(any( } else if #[cfg(target_vendor = "apple")] {
target_os = "macos",
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
))] {
mod libs_macos; mod libs_macos;
use libs_macos::native_libraries; use libs_macos::native_libraries;
} else if #[cfg(target_os = "illumos")] { } else if #[cfg(target_os = "illumos")] {
@ -472,10 +463,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
} }
if !any_frames { if !any_frames {
if let Some(name) = cx.object.search_symtab(addr as u64) { if let Some(name) = cx.object.search_symtab(addr as u64) {
call(Symbol::Symtab { call(Symbol::Symtab { name });
addr: addr as *mut c_void,
name,
});
} }
} }
}); });
@ -491,7 +479,7 @@ pub enum Symbol<'a> {
}, },
/// Couldn't find debug information, but we found it in the symbol table of /// Couldn't find debug information, but we found it in the symbol table of
/// the elf executable. /// the elf executable.
Symtab { addr: *mut c_void, name: &'a [u8] }, Symtab { name: &'a [u8] },
} }
impl Symbol<'_> { impl Symbol<'_> {

View File

@ -51,19 +51,15 @@ impl<'a> Object<'a> {
// note that the sections are 1-indexed because the zero section // note that the sections are 1-indexed because the zero section
// is special (apparently). // is special (apparently).
let mut symbols = Vec::new(); let mut symbols = Vec::new();
let mut i = 0; for (_, sym) in symtab.iter() {
let len = symtab.len(); if sym.derived_type() != object::pe::IMAGE_SYM_DTYPE_FUNCTION {
while i < len {
let sym = symtab.symbol(i).ok()?;
i += 1 + sym.number_of_aux_symbols as usize;
let section_number = sym.section_number.get(LE);
if sym.derived_type() != object::pe::IMAGE_SYM_DTYPE_FUNCTION || section_number == 0 {
continue; continue;
} }
let Some(section_index) = sym.section() else {
continue;
};
let addr = usize::try_from(sym.value.get(LE)).ok()?; let addr = usize::try_from(sym.value.get(LE)).ok()?;
let section = sections let section = sections.section(section_index).ok()?;
.section(usize::try_from(section_number).ok()?)
.ok()?;
let va = usize::try_from(section.virtual_address.get(LE)).ok()?; let va = usize::try_from(section.virtual_address.get(LE)).ok()?;
symbols.push((addr + va + image_base, sym)); symbols.push((addr + va + image_base, sym));
} }

View File

@ -281,20 +281,12 @@ impl<'a> Object<'a> {
} }
} }
fn object_mapping(path: &[u8]) -> Option<Mapping> { fn object_mapping(file: &object::read::ObjectMapFile<'_>) -> Option<Mapping> {
use super::mystd::ffi::OsStr; use super::mystd::ffi::OsStr;
use super::mystd::os::unix::prelude::*; use super::mystd::os::unix::prelude::*;
let map; let map = super::mmap(Path::new(OsStr::from_bytes(file.path())))?;
let member_name = file.member();
// `N_OSO` symbol names can be either `/path/to/object.o` or `/path/to/archive.a(object.o)`.
let member_name = if let Some((archive_path, member_name)) = split_archive_path(path) {
map = super::mmap(Path::new(OsStr::from_bytes(archive_path)))?;
Some(member_name)
} else {
map = super::mmap(Path::new(OsStr::from_bytes(path)))?;
None
};
Mapping::mk(map, |data, stash| { Mapping::mk(map, |data, stash| {
let data = match member_name { let data = match member_name {
Some(member_name) => { Some(member_name) => {
@ -314,16 +306,6 @@ fn object_mapping(path: &[u8]) -> Option<Mapping> {
}) })
} }
fn split_archive_path(path: &[u8]) -> Option<(&[u8], &[u8])> {
let (last, path) = path.split_last()?;
if *last != b')' {
return None;
}
let index = path.iter().position(|&x| x == b'(')?;
let (archive, rest) = path.split_at(index);
Some((archive, &rest[1..]))
}
pub(super) fn handle_split_dwarf<'data>( pub(super) fn handle_split_dwarf<'data>(
_package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>, _package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
_stash: &'data Stash, _stash: &'data Stash,

View File

@ -292,32 +292,15 @@ cfg_if::cfg_if! {
OptionCppSymbol(None) OptionCppSymbol(None)
} }
} }
} else {
use core::marker::PhantomData;
// Make sure to keep this zero-sized, so that the `cpp_demangle` feature
// has no cost when disabled.
struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
impl<'a> OptionCppSymbol<'a> {
fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
OptionCppSymbol(PhantomData)
}
fn none() -> OptionCppSymbol<'a> {
OptionCppSymbol(PhantomData)
}
}
} }
} }
/// A wrapper around a symbol name to provide ergonomic accessors to the /// A wrapper around a symbol name to provide ergonomic accessors to the
/// demangled name, the raw bytes, the raw string, etc. /// demangled name, the raw bytes, the raw string, etc.
// Allow dead code for when the `cpp_demangle` feature is not enabled.
#[allow(dead_code)]
pub struct SymbolName<'a> { pub struct SymbolName<'a> {
bytes: &'a [u8], bytes: &'a [u8],
demangled: Option<Demangle<'a>>, demangled: Option<Demangle<'a>>,
#[cfg(feature = "cpp_demangle")]
cpp_demangled: OptionCppSymbol<'a>, cpp_demangled: OptionCppSymbol<'a>,
} }
@ -327,6 +310,7 @@ impl<'a> SymbolName<'a> {
let str_bytes = str::from_utf8(bytes).ok(); let str_bytes = str::from_utf8(bytes).ok();
let demangled = str_bytes.and_then(|s| try_demangle(s).ok()); let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
#[cfg(feature = "cpp_demangle")]
let cpp = if demangled.is_none() { let cpp = if demangled.is_none() {
OptionCppSymbol::parse(bytes) OptionCppSymbol::parse(bytes)
} else { } else {
@ -336,6 +320,7 @@ impl<'a> SymbolName<'a> {
SymbolName { SymbolName {
bytes: bytes, bytes: bytes,
demangled: demangled, demangled: demangled,
#[cfg(feature = "cpp_demangle")]
cpp_demangled: cpp, cpp_demangled: cpp,
} }
} }
@ -380,65 +365,45 @@ fn format_symbol_name(
Ok(()) Ok(())
} }
cfg_if::cfg_if! { impl<'a> fmt::Display for SymbolName<'a> {
if #[cfg(feature = "cpp_demangle")] { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl<'a> fmt::Display for SymbolName<'a> { if let Some(ref s) = self.demangled {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { return s.fmt(f);
if let Some(ref s) = self.demangled { }
s.fmt(f)
} else if let Some(ref cpp) = self.cpp_demangled.0 { #[cfg(feature = "cpp_demangle")]
cpp.fmt(f) {
} else { if let Some(ref cpp) = self.cpp_demangled.0 {
format_symbol_name(fmt::Display::fmt, self.bytes, f) return cpp.fmt(f);
}
}
}
} else {
impl<'a> fmt::Display for SymbolName<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref s) = self.demangled {
s.fmt(f)
} else {
format_symbol_name(fmt::Display::fmt, self.bytes, f)
}
} }
} }
format_symbol_name(fmt::Display::fmt, self.bytes, f)
} }
} }
cfg_if::cfg_if! { impl<'a> fmt::Debug for SymbolName<'a> {
if #[cfg(all(feature = "std", feature = "cpp_demangle"))] { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl<'a> fmt::Debug for SymbolName<'a> { if let Some(ref s) = self.demangled {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { return s.fmt(f);
use std::fmt::Write;
if let Some(ref s) = self.demangled {
return s.fmt(f)
}
// This may to print if the demangled symbol isn't actually
// valid, so handle the error here gracefully by not propagating
// it outwards.
if let Some(ref cpp) = self.cpp_demangled.0 {
let mut s = String::new();
if write!(s, "{cpp}").is_ok() {
return s.fmt(f)
}
}
format_symbol_name(fmt::Debug::fmt, self.bytes, f)
}
} }
} else {
impl<'a> fmt::Debug for SymbolName<'a> { #[cfg(all(feature = "std", feature = "cpp_demangle"))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { {
if let Some(ref s) = self.demangled { use std::fmt::Write;
s.fmt(f)
} else { // This may to print if the demangled symbol isn't actually
format_symbol_name(fmt::Debug::fmt, self.bytes, f) // valid, so handle the error here gracefully by not propagating
// it outwards.
if let Some(ref cpp) = self.cpp_demangled.0 {
let mut s = String::new();
if write!(s, "{cpp}").is_ok() {
return s.fmt(f);
} }
} }
} }
format_symbol_name(fmt::Debug::fmt, self.bytes, f)
} }
} }
@ -453,7 +418,7 @@ cfg_if::cfg_if! {
/// While this function is always available it doesn't actually do anything on /// While this function is always available it doesn't actually do anything on
/// most implementations. Libraries like dbghelp or libbacktrace do not provide /// most implementations. Libraries like dbghelp or libbacktrace do not provide
/// facilities to deallocate state and manage the allocated memory. For now the /// facilities to deallocate state and manage the allocated memory. For now the
/// `gimli-symbolize` feature of this crate is the only feature where this /// `std` feature of this crate is the only feature where this
/// function has any effect. /// function has any effect.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn clear_symbol_cache() { pub fn clear_symbol_cache() {

View File

@ -38,6 +38,8 @@ cfg_if::cfg_if! {
pub use winapi::um::tlhelp32::*; pub use winapi::um::tlhelp32::*;
pub use winapi::um::winbase::*; pub use winapi::um::winbase::*;
pub use winapi::um::winnt::*; pub use winapi::um::winnt::*;
pub use winapi::um::winnls::*;
pub use winapi::um::stringapiset::*;
// Work around winapi not having this function on aarch64. // Work around winapi not having this function on aarch64.
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
@ -379,6 +381,7 @@ ffi! {
pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE; pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE;
pub const MAX_MODULE_NAME32: usize = 255; pub const MAX_MODULE_NAME32: usize = 255;
pub const MAX_PATH: usize = 260; pub const MAX_PATH: usize = 260;
pub const CP_UTF8: u32 = 65001;
pub type DWORD = u32; pub type DWORD = u32;
pub type PDWORD = *mut u32; pub type PDWORD = *mut u32;
@ -456,6 +459,16 @@ ffi! {
lpme: LPMODULEENTRY32W, lpme: LPMODULEENTRY32W,
) -> BOOL; ) -> BOOL;
pub fn lstrlenW(lpstring: PCWSTR) -> i32; pub fn lstrlenW(lpstring: PCWSTR) -> i32;
pub fn WideCharToMultiByte(
codepage: u32,
dwflags: u32,
lpwidecharstr: PCWSTR,
cchwidechar: i32,
lpmultibytestr: *mut i8,
cbmultibyte: i32,
lpdefaultchar: *const i8,
lpuseddefaultchar: *mut BOOL
) -> i32;
} }
} }

View File

@ -1,3 +1,4 @@
#![cfg(dbginfo = "collapsible")]
mod auxiliary; mod auxiliary;
macro_rules! pos { macro_rules! pos {
@ -6,6 +7,7 @@ macro_rules! pos {
}; };
} }
#[collapse_debuginfo(yes)]
macro_rules! check { macro_rules! check {
($($pos:expr),*) => ({ ($($pos:expr),*) => ({
verify(&[$($pos,)* pos!()]); verify(&[$($pos,)* pos!()]);
@ -29,7 +31,7 @@ fn doit() {
dir.pop(); dir.pop();
if cfg!(windows) { if cfg!(windows) {
dir.push("dylib_dep.dll"); dir.push("dylib_dep.dll");
} else if cfg!(target_os = "macos") { } else if cfg!(target_vendor = "apple") {
dir.push("libdylib_dep.dylib"); dir.push("libdylib_dep.dylib");
} else if cfg!(target_os = "aix") { } else if cfg!(target_os = "aix") {
dir.push("libdylib_dep.a"); dir.push("libdylib_dep.a");

View File

@ -230,18 +230,6 @@ fn many_threads() {
} }
} }
#[test]
#[cfg(feature = "rustc-serialize")]
fn is_rustc_serialize() {
extern crate rustc_serialize;
fn is_encode<T: rustc_serialize::Encodable>() {}
fn is_decode<T: rustc_serialize::Decodable>() {}
is_encode::<backtrace::Backtrace>();
is_decode::<backtrace::Backtrace>();
}
#[test] #[test]
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
fn is_serde() { fn is_serde() {

View File

@ -1 +0,0 @@
{"files":{"Cargo.lock":"36372e08a5cf4b713529f222928466b4d9bdc4116896bb9f121022c3b66502f1","Cargo.toml":"a261c28ccafada2884a75cab0e4e67326bafe720d58c937dc235521105982165","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"df01f5b4317d601e7de86743f9818aec9196abf9e298f5e47679b7a966ecd945","RELEASE-NOTES.md":"208162655e96cdf04949b6c0a53f24985095c8b188d7ea2c1017a23ce45e25eb","benches/benchmarks.rs":"da4a49294a7fcaf718f2b062a52ed669ca096abce6c57b4025efdd24825048c2","clippy.toml":"b26be4d15ed059985ce6994f11817fd7562046f46e460a0dc64dbb71cfc246d1","examples/base64.rs":"b75ead2199a9b4389c69fe6f1ae988176a263b8fc84e7a4fea1d7e5a41592078","icon_CLion.svg":"cffa044ba75cb998ee3306991dc4a3755ec2f39ab95ddd4b74bc21988389020f","src/alphabet.rs":"3461a34bd63c10cfe232deb5dd42e2ec2dfb5decd508caf31ec2a1826ad68131","src/chunked_encoder.rs":"edfdbb9a4329b80fb2c769ada81e234e00839e0fa85faaa70bacf40ce12e951c","src/decode.rs":"666ca75ccd975f0548d37312d2843ca4703b83697a044839bbefeba8f4f7874a","src/display.rs":"31bf3e19274a0b80dd8948a81ea535944f756ef5b88736124c940f5fe1e8c71c","src/encode.rs":"44ddcc162f3fe9817b6e857dda0a3b9197b90a657e5f71c44aacabf5431ccf7d","src/engine/general_purpose/decode.rs":"ba8a76d333ab96dd07b3f84bd6d405d690d2d17e84bd0878f05245a82dc16853","src/engine/general_purpose/decode_suffix.rs":"71ceb066b73e8cc833916e2cedbf0a01b07c2f16e30b2b2f63aff1c823874b51","src/engine/general_purpose/mod.rs":"9f49375fc03166a491acf464daa7a9e6540fdc2cca407da9a248e15640952c20","src/engine/mod.rs":"15210115e5f99e0d252a1240922deb1516778e318564f92a9d880a82fd82a55e","src/engine/naive.rs":"dc166010633e8de0fbff31e2f05d128506f3e0f34a6358c1a825b59a8ea1af0d","src/engine/tests.rs":"37bee2de07343bf5d37720f29cda291e8562f2363704e0ad91862d5991568d22","src/lib.rs":"3f964521aea13dbe49438ffed630a55471401da4c55c40506969697b649237f0","src/prelude.rs":"c1587138e5301ac797c5c362cb3638649b33f79c20c16db6f38ad44330540752","src/read/decoder.rs":"cc87daa4c52a23d1275352bccf07468baf2b60e90b2ac14f89a94254697cb83c","src/read/decoder_tests.rs":"edeee377e70095532be1625d0148de2273b739e9069a05e616d3e67877d92f1d","src/read/mod.rs":"e0b714eda02d16b1ffa6f78fd09b2f963e01c881b1f7c17b39db4e904be5e746","src/tests.rs":"90cb9f8a1ccb7c4ddc4f8618208e0031fc97e0df0e5aa466d6a5cf45d25967d8","src/write/encoder.rs":"c889c853249220fe2ddaeb77ee6e2ee2945f7db88cd6658ef89ff71b81255ea8","src/write/encoder_string_writer.rs":"0326c9d120369b9bbc35697b5b9b141bed24283374c93d5af1052eb042e47799","src/write/encoder_tests.rs":"28695a485b17cf5db73656aae5d90127f726e02c6d70efd83e5ab53a4cc17b38","src/write/mod.rs":"73cd98dadc9d712b3fefd9449d97e825e097397441b90588e0051e4d3b0911b9","tests/encode.rs":"5309f4538b1df611436f7bfba7409c725161b6f841b1bbf8d9890ae185de7d88","tests/tests.rs":"78efcf0dc4bb6ae52f7a91fcad89e44e4dce578224c36b4e6c1c306459be8500"},"package":"9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"}

1492
pve-rs/vendor/base64-0.21.7/Cargo.lock generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +0,0 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
rust-version = "1.48.0"
name = "base64"
version = "0.21.7"
authors = [
"Alice Maz <alice@alicemaz.com>",
"Marshall Pierce <marshall@mpierce.org>",
]
description = "encodes and decodes base64 as bytes or utf8"
documentation = "https://docs.rs/base64"
readme = "README.md"
keywords = [
"base64",
"utf8",
"encode",
"decode",
"no_std",
]
categories = ["encoding"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/marshallpierce/rust-base64"
[package.metadata.docs.rs]
rustdoc-args = ["--generate-link-to-definition"]
[profile.bench]
debug = 2
[profile.test]
opt-level = 3
[[example]]
name = "base64"
required-features = ["std"]
[[test]]
name = "tests"
required-features = ["alloc"]
[[test]]
name = "encode"
required-features = ["alloc"]
[[bench]]
name = "benchmarks"
harness = false
required-features = ["std"]
[dev-dependencies.clap]
version = "3.2.25"
features = ["derive"]
[dev-dependencies.criterion]
version = "0.4.0"
[dev-dependencies.once_cell]
version = "1"
[dev-dependencies.rand]
version = "0.8.5"
features = ["small_rng"]
[dev-dependencies.rstest]
version = "0.13.0"
[dev-dependencies.rstest_reuse]
version = "0.6.0"
[dev-dependencies.strum]
version = "0.25"
features = ["derive"]
[features]
alloc = []
default = ["std"]
std = ["alloc"]

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Alice Maz
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.

View File

@ -1,154 +0,0 @@
# [base64](https://crates.io/crates/base64)
[![](https://img.shields.io/crates/v/base64.svg)](https://crates.io/crates/base64) [![Docs](https://docs.rs/base64/badge.svg)](https://docs.rs/base64) [![CircleCI](https://circleci.com/gh/marshallpierce/rust-base64/tree/master.svg?style=shield)](https://circleci.com/gh/marshallpierce/rust-base64/tree/master) [![codecov](https://codecov.io/gh/marshallpierce/rust-base64/branch/master/graph/badge.svg)](https://codecov.io/gh/marshallpierce/rust-base64) [![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)
<a href="https://www.jetbrains.com/?from=rust-base64"><img src="/icon_CLion.svg" height="40px"/></a>
Made with CLion. Thanks to JetBrains for supporting open source!
It's base64. What more could anyone want?
This library's goals are to be *correct* and *fast*. It's thoroughly tested and widely used. It exposes functionality at
multiple levels of abstraction so you can choose the level of convenience vs performance that you want,
e.g. `decode_engine_slice` decodes into an existing `&mut [u8]` and is pretty fast (2.6GiB/s for a 3 KiB input),
whereas `decode_engine` allocates a new `Vec<u8>` and returns it, which might be more convenient in some cases, but is
slower (although still fast enough for almost any purpose) at 2.1 GiB/s.
See the [docs](https://docs.rs/base64) for all the details.
## FAQ
### I need to decode base64 with whitespace/null bytes/other random things interspersed in it. What should I do?
Remove non-base64 characters from your input before decoding.
If you have a `Vec` of base64, [retain](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain) can be used to
strip out whatever you need removed.
If you have a `Read` (e.g. reading a file or network socket), there are various approaches.
- Use [iter_read](https://crates.io/crates/iter-read) together with `Read`'s `bytes()` to filter out unwanted bytes.
- Implement `Read` with a `read()` impl that delegates to your actual `Read`, and then drops any bytes you don't want.
### I need to line-wrap base64, e.g. for MIME/PEM.
[line-wrap](https://crates.io/crates/line-wrap) does just that.
### I want canonical base64 encoding/decoding.
First, don't do this. You should no more expect Base64 to be canonical than you should expect compression algorithms to
produce canonical output across all usage in the wild (hint: they don't).
However, [people are drawn to their own destruction like moths to a flame](https://eprint.iacr.org/2022/361), so here we
are.
There are two opportunities for non-canonical encoding (and thus, detection of the same during decoding): the final bits
of the last encoded token in two or three token suffixes, and the `=` token used to inflate the suffix to a full four
tokens.
The trailing bits issue is unavoidable: with 6 bits available in each encoded token, 1 input byte takes 2 tokens,
with the second one having some bits unused. Same for two input bytes: 16 bits, but 3 tokens have 18 bits. Unless we
decide to stop shipping whole bytes around, we're stuck with those extra bits that a sneaky or buggy encoder might set
to 1 instead of 0.
The `=` pad bytes, on the other hand, are entirely a self-own by the Base64 standard. They do not affect decoding other
than to provide an opportunity to say "that padding is incorrect". Exabytes of storage and transfer have no doubt been
wasted on pointless `=` bytes. Somehow we all seem to be quite comfortable with, say, hex-encoded data just stopping
when it's done rather than requiring a confirmation that the author of the encoder could count to four. Anyway, there
are two ways to make pad bytes predictable: require canonical padding to the next multiple of four bytes as per the RFC,
or, if you control all producers and consumers, save a few bytes by requiring no padding (especially applicable to the
url-safe alphabet).
All `Engine` implementations must at a minimum support treating non-canonical padding of both types as an error, and
optionally may allow other behaviors.
## Rust version compatibility
The minimum supported Rust version is 1.48.0.
# Contributing
Contributions are very welcome. However, because this library is used widely, and in security-sensitive contexts, all
PRs will be carefully scrutinized. Beyond that, this sort of low level library simply needs to be 100% correct. Nobody
wants to chase bugs in encoding of any sort.
All this means that it takes me a fair amount of time to review each PR, so it might take quite a while to carve out the
free time to give each PR the attention it deserves. I will get to everyone eventually!
## Developing
Benchmarks are in `benches/`.
```bash
cargo bench
```
## no_std
This crate supports no_std. By default the crate targets std via the `std` feature. You can deactivate
the `default-features` to target `core` instead. In that case you lose out on all the functionality revolving
around `std::io`, `std::error::Error`, and heap allocations. There is an additional `alloc` feature that you can activate
to bring back the support for heap allocations.
## Profiling
On Linux, you can use [perf](https://perf.wiki.kernel.org/index.php/Main_Page) for profiling. Then compile the
benchmarks with `cargo bench --no-run`.
Run the benchmark binary with `perf` (shown here filtering to one particular benchmark, which will make the results
easier to read). `perf` is only available to the root user on most systems as it fiddles with event counters in your
CPU, so use `sudo`. We need to run the actual benchmark binary, hence the path into `target`. You can see the actual
full path with `cargo bench -v`; it will print out the commands it runs. If you use the exact path
that `bench` outputs, make sure you get the one that's for the benchmarks, not the tests. You may also want
to `cargo clean` so you have only one `benchmarks-` binary (they tend to accumulate).
```bash
sudo perf record target/release/deps/benchmarks-* --bench decode_10mib_reuse
```
Then analyze the results, again with perf:
```bash
sudo perf annotate -l
```
You'll see a bunch of interleaved rust source and assembly like this. The section with `lib.rs:327` is telling us that
4.02% of samples saw the `movzbl` aka bit shift as the active instruction. However, this percentage is not as exact as
it seems due to a phenomenon called *skid*. Basically, a consequence of how fancy modern CPUs are is that this sort of
instruction profiling is inherently inaccurate, especially in branch-heavy code.
```text
lib.rs:322 0.70 : 10698: mov %rdi,%rax
2.82 : 1069b: shr $0x38,%rax
: if morsel == decode_tables::INVALID_VALUE {
: bad_byte_index = input_index;
: break;
: };
: accum = (morsel as u64) << 58;
lib.rs:327 4.02 : 1069f: movzbl (%r9,%rax,1),%r15d
: // fast loop of 8 bytes at a time
: while input_index < length_of_full_chunks {
: let mut accum: u64;
:
: let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]);
: morsel = decode_table[(input_chunk >> 56) as usize];
lib.rs:322 3.68 : 106a4: cmp $0xff,%r15
: if morsel == decode_tables::INVALID_VALUE {
0.00 : 106ab: je 1090e <base64::decode_config_buf::hbf68a45fefa299c1+0x46e>
```
## Fuzzing
This uses [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz). See `fuzz/fuzzers` for the available fuzzing scripts.
To run, use an invocation like these:
```bash
cargo +nightly fuzz run roundtrip
cargo +nightly fuzz run roundtrip_no_pad
cargo +nightly fuzz run roundtrip_random_config -- -max_len=10240
cargo +nightly fuzz run decode_random
```
## License
This project is dual-licensed under MIT and Apache 2.0.

View File

@ -1,261 +0,0 @@
# 0.21.7
- Support getting an alphabet's contents as a str via `Alphabet::as_str()`
# 0.21.6
- Improved introductory documentation and example
# 0.21.5
- Add `Debug` and `Clone` impls for the general purpose Engine
# 0.21.4
- Make `encoded_len` `const`, allowing the creation of arrays sized to encode compile-time-known data lengths
# 0.21.3
- Implement `source` instead of `cause` on Error types
- Roll back MSRV to 1.48.0 so Debian can continue to live in a time warp
- Slightly faster chunked encoding for short inputs
- Decrease binary size
# 0.21.2
- Rollback MSRV to 1.57.0 -- only dev dependencies need 1.60, not the main code
# 0.21.1
- Remove the possibility of panicking during decoded length calculations
- `DecoderReader` no longer sometimes erroneously ignores
padding [#226](https://github.com/marshallpierce/rust-base64/issues/226)
## Breaking changes
- `Engine.internal_decode` return type changed
- Update MSRV to 1.60.0
# 0.21.0
## Migration
### Functions
| < 0.20 function | 0.21 equivalent |
|-------------------------|-------------------------------------------------------------------------------------|
| `encode()` | `engine::general_purpose::STANDARD.encode()` or `prelude::BASE64_STANDARD.encode()` |
| `encode_config()` | `engine.encode()` |
| `encode_config_buf()` | `engine.encode_string()` |
| `encode_config_slice()` | `engine.encode_slice()` |
| `decode()` | `engine::general_purpose::STANDARD.decode()` or `prelude::BASE64_STANDARD.decode()` |
| `decode_config()` | `engine.decode()` |
| `decode_config_buf()` | `engine.decode_vec()` |
| `decode_config_slice()` | `engine.decode_slice()` |
The short-lived 0.20 functions were the 0.13 functions with `config` replaced with `engine`.
### Padding
If applicable, use the preset engines `engine::STANDARD`, `engine::STANDARD_NO_PAD`, `engine::URL_SAFE`,
or `engine::URL_SAFE_NO_PAD`.
The `NO_PAD` ones require that padding is absent when decoding, and the others require that
canonical padding is present .
If you need the < 0.20 behavior that did not care about padding, or want to recreate < 0.20.0's predefined `Config`s
precisely, see the following table.
| 0.13.1 Config | 0.20.0+ alphabet | `encode_padding` | `decode_padding_mode` |
|-----------------|------------------|------------------|-----------------------|
| STANDARD | STANDARD | true | Indifferent |
| STANDARD_NO_PAD | STANDARD | false | Indifferent |
| URL_SAFE | URL_SAFE | true | Indifferent |
| URL_SAFE_NO_PAD | URL_SAFE | false | Indifferent |
# 0.21.0-rc.1
- Restore the ability to decode into a slice of precisely the correct length with `Engine.decode_slice_unchecked`.
- Add `Engine` as a `pub use` in `prelude`.
# 0.21.0-beta.2
## Breaking changes
- Re-exports of preconfigured engines in `engine` are removed in favor of `base64::prelude::...` that are better suited
to those who wish to `use` the entire path to a name.
# 0.21.0-beta.1
## Breaking changes
- `FastPortable` was only meant to be an interim name, and shouldn't have shipped in 0.20. It is now `GeneralPurpose` to
make its intended usage more clear.
- `GeneralPurpose` and its config are now `pub use`'d in the `engine` module for convenience.
- Change a few `from()` functions to be `new()`. `from()` causes confusing compiler errors because of confusion
with `From::from`, and is a little misleading because some of those invocations are not very cheap as one would
usually expect from a `from` call.
- `encode*` and `decode*` top level functions are now methods on `Engine`.
- `DEFAULT_ENGINE` was replaced by `engine::general_purpose::STANDARD`
- Predefined engine consts `engine::general_purpose::{STANDARD, STANDARD_NO_PAD, URL_SAFE, URL_SAFE_NO_PAD}`
- These are `pub use`d into `engine` as well
- The `*_slice` decode/encode functions now return an error instead of panicking when the output slice is too small
- As part of this, there isn't now a public way to decode into a slice _exactly_ the size needed for inputs that
aren't multiples of 4 tokens. If adding up to 2 bytes to always be a multiple of 3 bytes for the decode buffer is
a problem, file an issue.
## Other changes
- `decoded_len_estimate()` is provided to make it easy to size decode buffers correctly.
# 0.20.0
## Breaking changes
- Update MSRV to 1.57.0
- Decoding can now either ignore padding, require correct padding, or require no padding. The default is to require
correct padding.
- The `NO_PAD` config now requires that padding be absent when decoding.
## 0.20.0-alpha.1
### Breaking changes
- Extended the `Config` concept into the `Engine` abstraction, allowing the user to pick different encoding / decoding
implementations.
- What was formerly the only algorithm is now the `FastPortable` engine, so named because it's portable (works on
any CPU) and relatively fast.
- This opens the door to a portable constant-time
implementation ([#153](https://github.com/marshallpierce/rust-base64/pull/153),
presumably `ConstantTimePortable`?) for security-sensitive applications that need side-channel resistance, and
CPU-specific SIMD implementations for more speed.
- Standard base64 per the RFC is available via `DEFAULT_ENGINE`. To use different alphabets or other settings (
padding, etc), create your own engine instance.
- `CharacterSet` is now `Alphabet` (per the RFC), and allows creating custom alphabets. The corresponding tables that
were previously code-generated are now built dynamically.
- Since there are already multiple breaking changes, various functions are renamed to be more consistent and
discoverable.
- MSRV is now 1.47.0 to allow various things to use `const fn`.
- `DecoderReader` now owns its inner reader, and can expose it via `into_inner()`. For symmetry, `EncoderWriter` can do
the same with its writer.
- `encoded_len` is now public so you can size encode buffers precisely.
# 0.13.1
- More precise decode buffer sizing, avoiding unnecessary allocation in `decode_config`.
# 0.13.0
- Config methods are const
- Added `EncoderStringWriter` to allow encoding directly to a String
- `EncoderWriter` now owns its delegate writer rather than keeping a reference to it (though refs still work)
- As a consequence, it is now possible to extract the delegate writer from an `EncoderWriter` via `finish()`, which
returns `Result<W>` instead of `Result<()>`. If you were calling `finish()` explicitly, you will now need to
use `let _ = foo.finish()` instead of just `foo.finish()` to avoid a warning about the unused value.
- When decoding input that has both an invalid length and an invalid symbol as the last byte, `InvalidByte` will be
emitted instead of `InvalidLength` to make the problem more obvious.
# 0.12.2
- Add `BinHex` alphabet
# 0.12.1
- Add `Bcrypt` alphabet
# 0.12.0
- A `Read` implementation (`DecoderReader`) to let users transparently decoded data from a b64 input source
- IMAP's modified b64 alphabet
- Relaxed type restrictions to just `AsRef<[ut8]>` for main `encode*`/`decode*` functions
- A minor performance improvement in encoding
# 0.11.0
- Minimum rust version 1.34.0
- `no_std` is now supported via the two new features `alloc` and `std`.
# 0.10.1
- Minimum rust version 1.27.2
- Fix bug in streaming encoding ([#90](https://github.com/marshallpierce/rust-base64/pull/90)): if the underlying writer
didn't write all the bytes given to it, the remaining bytes would not be retried later. See the docs
on `EncoderWriter::write`.
- Make it configurable whether or not to return an error when decoding detects excess trailing bits.
# 0.10.0
- Remove line wrapping. Line wrapping was never a great conceptual fit in this library, and other features (streaming
encoding, etc) either couldn't support it or could support only special cases of it with a great increase in
complexity. Line wrapping has been pulled out into a [line-wrap](https://crates.io/crates/line-wrap) crate, so it's
still available if you need it.
- `Base64Display` creation no longer uses a `Result` because it can't fail, which means its helper methods for
common
configs that `unwrap()` for you are no longer needed
- Add a streaming encoder `Write` impl to transparently base64 as you write.
- Remove the remaining `unsafe` code.
- Remove whitespace stripping to simplify `no_std` support. No out of the box configs use it, and it's trivial to do
yourself if needed: `filter(|b| !b" \n\t\r\x0b\x0c".contains(b)`.
- Detect invalid trailing symbols when decoding and return an error rather than silently ignoring them.
# 0.9.3
- Update safemem
# 0.9.2
- Derive `Clone` for `DecodeError`.
# 0.9.1
- Add support for `crypt(3)`'s base64 variant.
# 0.9.0
- `decode_config_slice` function for no-allocation decoding, analogous to `encode_config_slice`
- Decode performance optimization
# 0.8.0
- `encode_config_slice` function for no-allocation encoding
# 0.7.0
- `STANDARD_NO_PAD` config
- `Base64Display` heap-free wrapper for use in format strings, etc
# 0.6.0
- Decode performance improvements
- Use `unsafe` in fewer places
- Added fuzzers
# 0.5.2
- Avoid usize overflow when calculating length
- Better line wrapping performance
# 0.5.1
- Temporarily disable line wrapping
- Add Apache 2.0 license
# 0.5.0
- MIME support, including configurable line endings and line wrapping
- Removed `decode_ws`
- Renamed `Base64Error` to `DecodeError`
# 0.4.1
- Allow decoding a `AsRef<[u8]>` instead of just a `&str`
# 0.4.0
- Configurable padding
- Encode performance improvements
# 0.3.0
- Added encode/decode functions that do not allocate their own storage
- Decode performance improvements
- Extraneous padding bytes are no longer ignored. Now, an error will be returned.

View File

@ -1,239 +0,0 @@
#[macro_use]
extern crate criterion;
use base64::{
display,
engine::{general_purpose::STANDARD, Engine},
write,
};
use criterion::{black_box, Bencher, BenchmarkId, Criterion, Throughput};
use rand::{Rng, SeedableRng};
use std::io::{self, Read, Write};
fn do_decode_bench(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
fill(&mut v);
let encoded = STANDARD.encode(&v);
b.iter(|| {
let orig = STANDARD.decode(&encoded);
black_box(&orig);
});
}
fn do_decode_bench_reuse_buf(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
fill(&mut v);
let encoded = STANDARD.encode(&v);
let mut buf = Vec::new();
b.iter(|| {
STANDARD.decode_vec(&encoded, &mut buf).unwrap();
black_box(&buf);
buf.clear();
});
}
fn do_decode_bench_slice(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
fill(&mut v);
let encoded = STANDARD.encode(&v);
let mut buf = vec![0; size];
b.iter(|| {
STANDARD.decode_slice(&encoded, &mut buf).unwrap();
black_box(&buf);
});
}
fn do_decode_bench_stream(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size * 3 / 4);
fill(&mut v);
let encoded = STANDARD.encode(&v);
let mut buf = vec![0; size];
buf.truncate(0);
b.iter(|| {
let mut cursor = io::Cursor::new(&encoded[..]);
let mut decoder = base64::read::DecoderReader::new(&mut cursor, &STANDARD);
decoder.read_to_end(&mut buf).unwrap();
buf.clear();
black_box(&buf);
});
}
fn do_encode_bench(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size);
fill(&mut v);
b.iter(|| {
let e = STANDARD.encode(&v);
black_box(&e);
});
}
fn do_encode_bench_display(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size);
fill(&mut v);
b.iter(|| {
let e = format!("{}", display::Base64Display::new(&v, &STANDARD));
black_box(&e);
});
}
fn do_encode_bench_reuse_buf(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size);
fill(&mut v);
let mut buf = String::new();
b.iter(|| {
STANDARD.encode_string(&v, &mut buf);
buf.clear();
});
}
fn do_encode_bench_slice(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size);
fill(&mut v);
// conservative estimate of encoded size
let mut buf = vec![0; v.len() * 2];
b.iter(|| STANDARD.encode_slice(&v, &mut buf).unwrap());
}
fn do_encode_bench_stream(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size);
fill(&mut v);
let mut buf = Vec::new();
buf.reserve(size * 2);
b.iter(|| {
buf.clear();
let mut stream_enc = write::EncoderWriter::new(&mut buf, &STANDARD);
stream_enc.write_all(&v).unwrap();
stream_enc.flush().unwrap();
});
}
fn do_encode_bench_string_stream(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size);
fill(&mut v);
b.iter(|| {
let mut stream_enc = write::EncoderStringWriter::new(&STANDARD);
stream_enc.write_all(&v).unwrap();
stream_enc.flush().unwrap();
let _ = stream_enc.into_inner();
});
}
fn do_encode_bench_string_reuse_buf_stream(b: &mut Bencher, &size: &usize) {
let mut v: Vec<u8> = Vec::with_capacity(size);
fill(&mut v);
let mut buf = String::new();
b.iter(|| {
buf.clear();
let mut stream_enc = write::EncoderStringWriter::from_consumer(&mut buf, &STANDARD);
stream_enc.write_all(&v).unwrap();
stream_enc.flush().unwrap();
let _ = stream_enc.into_inner();
});
}
fn fill(v: &mut Vec<u8>) {
let cap = v.capacity();
// weak randomness is plenty; we just want to not be completely friendly to the branch predictor
let mut r = rand::rngs::SmallRng::from_entropy();
while v.len() < cap {
v.push(r.gen::<u8>());
}
}
const BYTE_SIZES: [usize; 5] = [3, 50, 100, 500, 3 * 1024];
// Benchmarks over these byte sizes take longer so we will run fewer samples to
// keep the benchmark runtime reasonable.
const LARGE_BYTE_SIZES: [usize; 3] = [3 * 1024 * 1024, 10 * 1024 * 1024, 30 * 1024 * 1024];
fn encode_benchmarks(c: &mut Criterion, label: &str, byte_sizes: &[usize]) {
let mut group = c.benchmark_group(label);
group
.warm_up_time(std::time::Duration::from_millis(500))
.measurement_time(std::time::Duration::from_secs(3));
for size in byte_sizes {
group
.throughput(Throughput::Bytes(*size as u64))
.bench_with_input(BenchmarkId::new("encode", size), size, do_encode_bench)
.bench_with_input(
BenchmarkId::new("encode_display", size),
size,
do_encode_bench_display,
)
.bench_with_input(
BenchmarkId::new("encode_reuse_buf", size),
size,
do_encode_bench_reuse_buf,
)
.bench_with_input(
BenchmarkId::new("encode_slice", size),
size,
do_encode_bench_slice,
)
.bench_with_input(
BenchmarkId::new("encode_reuse_buf_stream", size),
size,
do_encode_bench_stream,
)
.bench_with_input(
BenchmarkId::new("encode_string_stream", size),
size,
do_encode_bench_string_stream,
)
.bench_with_input(
BenchmarkId::new("encode_string_reuse_buf_stream", size),
size,
do_encode_bench_string_reuse_buf_stream,
);
}
group.finish();
}
fn decode_benchmarks(c: &mut Criterion, label: &str, byte_sizes: &[usize]) {
let mut group = c.benchmark_group(label);
for size in byte_sizes {
group
.warm_up_time(std::time::Duration::from_millis(500))
.measurement_time(std::time::Duration::from_secs(3))
.throughput(Throughput::Bytes(*size as u64))
.bench_with_input(BenchmarkId::new("decode", size), size, do_decode_bench)
.bench_with_input(
BenchmarkId::new("decode_reuse_buf", size),
size,
do_decode_bench_reuse_buf,
)
.bench_with_input(
BenchmarkId::new("decode_slice", size),
size,
do_decode_bench_slice,
)
.bench_with_input(
BenchmarkId::new("decode_stream", size),
size,
do_decode_bench_stream,
);
}
group.finish();
}
fn bench(c: &mut Criterion) {
encode_benchmarks(c, "encode_small_input", &BYTE_SIZES[..]);
encode_benchmarks(c, "encode_large_input", &LARGE_BYTE_SIZES[..]);
decode_benchmarks(c, "decode_small_input", &BYTE_SIZES[..]);
decode_benchmarks(c, "decode_large_input", &LARGE_BYTE_SIZES[..]);
}
criterion_group!(benches, bench);
criterion_main!(benches);

View File

@ -1 +0,0 @@
msrv = "1.48.0"

View File

@ -1,81 +0,0 @@
use std::fs::File;
use std::io::{self, Read};
use std::path::PathBuf;
use std::process;
use base64::{alphabet, engine, read, write};
use clap::Parser;
#[derive(Clone, Debug, Parser, strum::EnumString, Default)]
#[strum(serialize_all = "kebab-case")]
enum Alphabet {
#[default]
Standard,
UrlSafe,
}
/// Base64 encode or decode FILE (or standard input), to standard output.
#[derive(Debug, Parser)]
struct Opt {
/// Decode the base64-encoded input (default: encode the input as base64).
#[structopt(short = 'd', long = "decode")]
decode: bool,
/// The encoding alphabet: "standard" (default) or "url-safe".
#[structopt(long = "alphabet")]
alphabet: Option<Alphabet>,
/// Omit padding characters while encoding, and reject them while decoding.
#[structopt(short = 'p', long = "no-padding")]
no_padding: bool,
/// The file to encode or decode.
#[structopt(name = "FILE", parse(from_os_str))]
file: Option<PathBuf>,
}
fn main() {
let opt = Opt::parse();
let stdin;
let mut input: Box<dyn Read> = match opt.file {
None => {
stdin = io::stdin();
Box::new(stdin.lock())
}
Some(ref f) if f.as_os_str() == "-" => {
stdin = io::stdin();
Box::new(stdin.lock())
}
Some(f) => Box::new(File::open(f).unwrap()),
};
let alphabet = opt.alphabet.unwrap_or_default();
let engine = engine::GeneralPurpose::new(
&match alphabet {
Alphabet::Standard => alphabet::STANDARD,
Alphabet::UrlSafe => alphabet::URL_SAFE,
},
match opt.no_padding {
true => engine::general_purpose::NO_PAD,
false => engine::general_purpose::PAD,
},
);
let stdout = io::stdout();
let mut stdout = stdout.lock();
let r = if opt.decode {
let mut decoder = read::DecoderReader::new(&mut input, &engine);
io::copy(&mut decoder, &mut stdout)
} else {
let mut encoder = write::EncoderWriter::new(&mut stdout, &engine);
io::copy(&mut input, &mut encoder)
};
if let Err(e) = r {
eprintln!(
"Base64 {} failed with {}",
if opt.decode { "decode" } else { "encode" },
e
);
process::exit(1);
}
}

View File

@ -1,34 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 128 128">
<defs>
<linearGradient id="linear-gradient" x1="40.69" y1="-676.56" x2="83.48" y2="-676.56" gradientTransform="matrix(1, 0, 0, -1, 0, -648.86)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ed358c"/>
<stop offset="0.16" stop-color="#e9388c"/>
<stop offset="0.3" stop-color="#de418c"/>
<stop offset="0.43" stop-color="#cc508c"/>
<stop offset="0.57" stop-color="#b2658d"/>
<stop offset="0.7" stop-color="#90808d"/>
<stop offset="0.83" stop-color="#67a18e"/>
<stop offset="0.95" stop-color="#37c78f"/>
<stop offset="1" stop-color="#22d88f"/>
</linearGradient>
<linearGradient id="linear-gradient-2" x1="32.58" y1="-665.27" x2="13.76" y2="-791.59" gradientTransform="matrix(1, 0, 0, -1, 0, -648.86)" gradientUnits="userSpaceOnUse">
<stop offset="0.09" stop-color="#22d88f"/>
<stop offset="0.9" stop-color="#029de0"/>
</linearGradient>
<linearGradient id="linear-gradient-3" x1="116.68" y1="-660.66" x2="-12.09" y2="-796.66" xlink:href="#linear-gradient-2"/>
<linearGradient id="linear-gradient-4" x1="73.35" y1="-739.1" x2="122.29" y2="-746.06" xlink:href="#linear-gradient-2"/>
</defs>
<title>icon_CLion</title>
<g>
<polygon points="49.2 51.8 40.6 55.4 48.4 0 77.8 16.2 49.2 51.8" fill="url(#linear-gradient)"/>
<polygon points="44.6 76.8 48.8 0 11.8 23.2 0 94 44.6 76.8" fill="url(#linear-gradient-2)"/>
<polygon points="125.4 38.4 109 4.8 77.8 16.2 55 41.4 0 94 41.6 124.4 93.6 77.2 125.4 38.4" fill="url(#linear-gradient-3)"/>
<polygon points="53.8 54.6 46.6 98.4 75.8 121 107.8 128 128 82.4 53.8 54.6" fill="url(#linear-gradient-4)"/>
</g>
<g>
<rect x="24" y="24" width="80" height="80"/>
<rect x="31.6" y="89" width="30" height="5" fill="#fff"/>
<path d="M31,51.2h0A16.83,16.83,0,0,1,48.2,34c6.2,0,10,2,13,5.2l-4.6,5.4c-2.6-2.4-5.2-3.8-8.4-3.8-5.6,0-9.6,4.6-9.6,10.4h0c0,5.6,4,10.4,9.6,10.4,3.8,0,6.2-1.6,8.8-3.8l4.6,4.6c-3.4,3.6-7.2,6-13.6,6A17,17,0,0,1,31,51.2" fill="#fff"/>
<path d="M66.6,34.4H74v27H88.4v6.2H66.6V34.4Z" fill="#fff"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

Some files were not shown because too many files have changed in this diff Show More