summaryrefslogtreecommitdiffstats
path: root/vendor/gix-features
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-features')
-rw-r--r--vendor/gix-features/.cargo-checksum.json1
-rw-r--r--vendor/gix-features/CHANGELOG.md1174
-rw-r--r--vendor/gix-features/Cargo.toml180
-rw-r--r--vendor/gix-features/src/cache.rs76
-rw-r--r--vendor/gix-features/src/decode.rs38
-rw-r--r--vendor/gix-features/src/fs.rs246
-rw-r--r--vendor/gix-features/src/hash.rs190
-rw-r--r--vendor/gix-features/src/interrupt.rs125
-rw-r--r--vendor/gix-features/src/io.rs94
-rw-r--r--vendor/gix-features/src/lib.rs64
-rw-r--r--vendor/gix-features/src/parallel/eager_iter.rs124
-rw-r--r--vendor/gix-features/src/parallel/in_order.rs83
-rw-r--r--vendor/gix-features/src/parallel/in_parallel.rs211
-rw-r--r--vendor/gix-features/src/parallel/mod.rs179
-rw-r--r--vendor/gix-features/src/parallel/reduce.rs279
-rw-r--r--vendor/gix-features/src/parallel/serial.rs135
-rw-r--r--vendor/gix-features/src/progress.rs139
-rw-r--r--vendor/gix-features/src/threading.rs100
-rw-r--r--vendor/gix-features/src/zlib/mod.rs47
-rw-r--r--vendor/gix-features/src/zlib/stream/deflate/mod.rs96
-rw-r--r--vendor/gix-features/src/zlib/stream/deflate/tests.rs101
-rw-r--r--vendor/gix-features/src/zlib/stream/inflate.rs57
-rw-r--r--vendor/gix-features/src/zlib/stream/mod.rs4
-rw-r--r--vendor/gix-features/tests/hash.rs13
-rw-r--r--vendor/gix-features/tests/parallel/in_order_iter.rs54
-rw-r--r--vendor/gix-features/tests/parallel/mod.rs125
-rw-r--r--vendor/gix-features/tests/parallel_shared.rs1
-rw-r--r--vendor/gix-features/tests/parallel_shared_threaded.rs1
-rw-r--r--vendor/gix-features/tests/parallel_threaded.rs122
-rw-r--r--vendor/gix-features/tests/pipe.rs117
30 files changed, 4176 insertions, 0 deletions
diff --git a/vendor/gix-features/.cargo-checksum.json b/vendor/gix-features/.cargo-checksum.json
new file mode 100644
index 000000000..14b6a61d4
--- /dev/null
+++ b/vendor/gix-features/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"9c722584b07c154a9b92e2fb2db53aaaa0e2604a43703c6c0230cf07253e1d55","Cargo.toml":"29a3ce857f725c72c163aee07f776269d50be36b5c3f08cc3389cc3b8e2c08ea","src/cache.rs":"0ae91d58914d8e6ac2d2d6fa52522364db6ea8e81421614a36b4009a184a4705","src/decode.rs":"bf614320c6b69556da40d8412c73fb6a8648c80b7d75b9b2525eb62ac6c8d802","src/fs.rs":"0f7d98d943c642bc0fcbdf51990ee8d557397515f85be9e858f290468d0812b4","src/hash.rs":"95c5fe92beb1807b269bb86764c7ebb49363167a3d97931e06a20643b4c68f5e","src/interrupt.rs":"e9e91b50eadae55e4b2ca33482093697960a9dd4c3b7eaf7d1efb0dce495aa1e","src/io.rs":"6e4b80ce21d914e670629e9dbda13a8ebf0f523beb9036558236a94d00e88311","src/lib.rs":"e7ffd154849245bacb1f9c00e709b0b1c8d338755d7624507fbf3fd0adeffc0a","src/parallel/eager_iter.rs":"3bfb3e44478243afb7bfc68089c4c715131c2ce6d494450ce408001a28bf4dc9","src/parallel/in_order.rs":"a1c8c2f6ee4a91d6103f3fc6f27525e309cccc49ffc661d1403dbcdc57d120ad","src/parallel/in_parallel.rs":"d7182854eccf0f5d0af589f5efec02d0c14bbe9906920311e5d7516ddcc4fc31","src/parallel/mod.rs":"d74cf6da2ec807fbb34e75370470f34e5cbd9ae3440e5bac0d7def1167978521","src/parallel/reduce.rs":"3ed124c86af1860dbb07f01ad0249714955327c687bda7ee024cf3a3baf94186","src/parallel/serial.rs":"3cabe5acced4c0bbd79c71042c4fe71fb42bc8503416147bf7e94f14d1c66ebc","src/progress.rs":"714f17c069e8da215cb6359a1934d555121d302d3d4179d793e914f9bc488cf7","src/threading.rs":"241bec714a4ff6d94cf74804ac7e3ac172bda5394be799df4958740cf48e4bbb","src/zlib/mod.rs":"fd27b104abe2d93b71123e4f16640bc32703d6d09ba8e800c430dcfd72a07b06","src/zlib/stream/deflate/mod.rs":"8a69ea48012633f322e6bccc14dccaa29e8960bad7135f4abe924a38afc73c59","src/zlib/stream/deflate/tests.rs":"1a42b2c4fdbe8383d75ebdaae825c9ab0ac03a461e2177026e6be57c1101b37e","src/zlib/stream/inflate.rs":"d5bb3b858e42aecb263f2b24f110fffe22e94b507e963f156831868119dc3f20","src/zlib/stream/mod.rs":"0af2967eb75a07308c789a4187490cc7c36693b7f7d8a4f7705f3b4b90568f6f","tests/hash.rs":"d03f99e2ed1f00066e14212e7e65ee3ae076df42935d38c47d5a563b69367e8c","tests/parallel/in_order_iter.rs":"acd746c25929406748de5080b7ae5dcb2516269f037944d7aa84802520b885b4","tests/parallel/mod.rs":"c6b6d1b1db1a59f07fac93ed7ce10558a46eba38cfa3fc50659d3262ce58e313","tests/parallel_shared.rs":"5d8dabaa42fce087e2ec57843cfe69f2be1ca2fa3518030b5a31aeaa706675e0","tests/parallel_shared_threaded.rs":"5d8dabaa42fce087e2ec57843cfe69f2be1ca2fa3518030b5a31aeaa706675e0","tests/parallel_threaded.rs":"02cfb39c7e81bca7e92a851c731e993cad13eff87ec1f8a228d74761ec964f7a","tests/pipe.rs":"54c070bb8dc5f6b495131ff4342a715b0e6491a68d2477143eeb76b7d05f4019"},"package":"5e6a9dfa7b3c1a99315203e8b97f8f99f3bd95731590607abeaa5ca31bc41fe3"} \ No newline at end of file
diff --git a/vendor/gix-features/CHANGELOG.md b/vendor/gix-features/CHANGELOG.md
new file mode 100644
index 000000000..7f34fbe23
--- /dev/null
+++ b/vendor/gix-features/CHANGELOG.md
@@ -0,0 +1,1174 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## 0.28.0 (2023-03-04)
+
+### New Features (BREAKING)
+
+ - <csr-id-571ec0d7c3e1eb167d55daa6551bd2b27d3c5b25/> use `std::thread::scope()` instead of `crossbeam-utils::thread::scope()`.
+ This cuts a direct dependency.
+ We can't removed `crossbeam-channel` yet due to the need for single-produce-multiple-consumer
+ channels.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 3 commits contributed to the release over the course of 1 calendar day.
+ - 3 days passed between releases.
+ - 1 commit was understood as [conventional](https://www.conventionalcommits.org).
+ - 0 issues like '(#ID)' were seen in commit messages
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **Uncategorized**
+ - Prepare changelogs prior to release of `gix-pack` ([`6db30ef`](https://github.com/Byron/gitoxide/commit/6db30ef6b5e931bbf12135507a3d922051de4d4b))
+ - Merge branch 'adjustments-for-cargo' ([`04ab852`](https://github.com/Byron/gitoxide/commit/04ab852f3be76bdf151affa25cf4b999b127bdfe))
+ - Use `std::thread::scope()` instead of `crossbeam-utils::thread::scope()`. ([`571ec0d`](https://github.com/Byron/gitoxide/commit/571ec0d7c3e1eb167d55daa6551bd2b27d3c5b25))
+</details>
+
+## 0.27.0 (2023-03-01)
+
+<csr-id-cce96ee1382d3d56d77820a2aba6e2d17b52f91c/>
+
+### Chore
+
+ - <csr-id-cce96ee1382d3d56d77820a2aba6e2d17b52f91c/> replace `quick-error` with `thiserror`
+ This increases the compile time of the crate alone if there is no proc-macro
+ in the dependency tree, but will ever so slightly improve compile times for `gix`
+ as a whole.
+
+### New Features
+
+ - <csr-id-7a442313c57f58fec5217484f268516711c3d52b/> make `bytesize` available in `progress`.
+ Note that it is stubbed out unless the `progress-unit-bytes` feature is set.
+ - <csr-id-7f6a807ea506358b6dc4fd0c7a648770f1dc91e9/> add `progress::count_with_decimals()` and `progress-unit-*` feature toggles.
+ The new feature toggles allow controlling the inclusion of the `bytesize` and `human_format`
+ crates, which can be toggled with the `progress-unit-bytes` and `progress-unit-human-numbers` respectively.
+
+ Without these features, the respective functions exist but don't provide special formatting, making bytes and
+ larger numbers harder to read.
+
+### Bug Fixes
+
+ - <csr-id-264f78a508d3030cb346623f57ac75add7682169/> remove `num_cpus` in favor of `std::thread::available_parallelism()`.
+ `num_cpus` was needed back in the days when `std` didn't support such
+ functionality yet.
+
+### Changed (BREAKING)
+
+ - <csr-id-0cc548041a861be21001462cbe0ef29b1d61d1c4/> use new `dep:` syntax to hide optional features from feature-set.
+ That way, the set of features is clearly defined and controlled.
+ This migth break applications who relied on direect access to features named
+ after optional dependencies.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 11 commits contributed to the release over the course of 3 calendar days.
+ - 8 days passed between releases.
+ - 5 commits were understood as [conventional](https://www.conventionalcommits.org).
+ - 0 issues like '(#ID)' were seen in commit messages
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **Uncategorized**
+ - Release gix-features v0.27.0, gix-actor v0.18.0, gix-quote v0.4.3, gix-attributes v0.9.0, gix-object v0.27.0, gix-ref v0.25.0, gix-config v0.17.0, gix-url v0.14.0, gix-credentials v0.10.0, gix-diff v0.27.0, gix-discover v0.14.0, gix-hashtable v0.1.2, gix-bitmap v0.2.2, gix-traverse v0.23.0, gix-index v0.13.0, gix-mailmap v0.10.0, gix-pack v0.31.0, gix-odb v0.41.0, gix-transport v0.26.0, gix-protocol v0.27.0, gix-revision v0.11.0, gix-refspec v0.8.0, gix-worktree v0.13.0, gix v0.38.0 ([`e6cc618`](https://github.com/Byron/gitoxide/commit/e6cc6184a7a49dbc2503c1c1bdd3688ca5cec5fe))
+ - Adjust manifests prior to release ([`addd789`](https://github.com/Byron/gitoxide/commit/addd78958fdd1e54eb702854e96079539d01965a))
+ - Prepare changelogs prior to release ([`94c99c7`](https://github.com/Byron/gitoxide/commit/94c99c71520f33269cc8dbc26f82a74747cc7e16))
+ - Merge branch 'adjustments-for-cargo' ([`d686d94`](https://github.com/Byron/gitoxide/commit/d686d94e1030a8591ba074757d56927a346c8351))
+ - Depend on latest version of `prodash` for performance improvements. ([`5d00324`](https://github.com/Byron/gitoxide/commit/5d003242abe82b1604e2188d49dec9690ebb2a6a))
+ - Make `bytesize` available in `progress`. ([`7a44231`](https://github.com/Byron/gitoxide/commit/7a442313c57f58fec5217484f268516711c3d52b))
+ - Add `progress::count_with_decimals()` and `progress-unit-*` feature toggles. ([`7f6a807`](https://github.com/Byron/gitoxide/commit/7f6a807ea506358b6dc4fd0c7a648770f1dc91e9))
+ - Use new `dep:` syntax to hide optional features from feature-set. ([`0cc5480`](https://github.com/Byron/gitoxide/commit/0cc548041a861be21001462cbe0ef29b1d61d1c4))
+ - Remove `num_cpus` in favor of `std::thread::available_parallelism()`. ([`264f78a`](https://github.com/Byron/gitoxide/commit/264f78a508d3030cb346623f57ac75add7682169))
+ - Replace `quick-error` with `thiserror` ([`cce96ee`](https://github.com/Byron/gitoxide/commit/cce96ee1382d3d56d77820a2aba6e2d17b52f91c))
+ - Make fmt ([`8ef1cb2`](https://github.com/Byron/gitoxide/commit/8ef1cb293434c7b9e1fda4a6963368e0435920a9))
+</details>
+
+## 0.26.5 (2023-02-20)
+
+### Bug Fixes
+
+ - <csr-id-e14dc7d475373d2c266e84ff8f1826c68a34ab92/> note that crates have been renamed from `git-*` to `gix-*`.
+ This also means that the `git-*` prefixed crates of the `gitoxide` project
+ are effectively unmaintained.
+ Use the crates with the `gix-*` prefix instead.
+
+ If you were using `git-repository`, then `gix` is its substitute.
+ - <csr-id-135d317065aae87af302beb6c26bb6ca8e30b6aa/> compatibility with `bstr` v1.3, use `*.as_bytes()` instead of `.as_ref()`.
+ `as_ref()` relies on a known target type which isn't always present. However, once
+ there is only one implementation, that's no problem, but when that changes compilation
+ fails due to ambiguity.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 2 commits contributed to the release.
+ - 3 days passed between releases.
+ - 1 commit was understood as [conventional](https://www.conventionalcommits.org).
+ - 0 issues like '(#ID)' were seen in commit messages
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **Uncategorized**
+ - Release gix-date v0.4.3, gix-hash v0.10.3, gix-features v0.26.5, gix-actor v0.17.2, gix-glob v0.5.5, gix-path v0.7.2, gix-quote v0.4.2, gix-attributes v0.8.3, gix-validate v0.7.3, gix-object v0.26.2, gix-ref v0.24.1, gix-config v0.16.2, gix-command v0.2.4, gix-url v0.13.3, gix-credentials v0.9.2, gix-discover v0.13.1, gix-index v0.12.4, gix-mailmap v0.9.3, gix-pack v0.30.3, gix-packetline v0.14.3, gix-transport v0.25.6, gix-protocol v0.26.4, gix-revision v0.10.4, gix-refspec v0.7.3, gix-worktree v0.12.3, gix v0.36.1 ([`9604783`](https://github.com/Byron/gitoxide/commit/96047839a20a657a559376b0b14c65aeab96acbd))
+ - Compatibility with `bstr` v1.3, use `*.as_bytes()` instead of `.as_ref()`. ([`135d317`](https://github.com/Byron/gitoxide/commit/135d317065aae87af302beb6c26bb6ca8e30b6aa))
+</details>
+
+## 0.26.4 (2023-02-17)
+
+<csr-id-5bf0034fb3918e57562b7089ceba83d63a1854bf/>
+<csr-id-ab6f98b905f13ed2a7c0c483f34fab63141fbc5b/>
+<csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/>
+<csr-id-361892ca15aa648802f6701ab6a5a30aedde3449/>
+
+### New Features (BREAKING)
+
+ - <csr-id-0f27c67c92fc0bc23a6712b5c4c730ad6a0156bf/> add support for explicit non-parallel iteration.
+ That way we can allow the implementation to choose whether they
+ need greatest speed at some cost or not.
+
+ This also allows us to create a new thread-pool on each iteration
+ as those who expect high cost or many files will likely chose to do
+ that instead of single-threaded iteration, which nicely contains the
+ threads needed and avoids keeping them alive as part of some global pool.
+ - <csr-id-3b29fc18672c0176684c797a0f16f85d09369bf8/> make jwalk fully optional
+ - <csr-id-d078d6ee76a80d1dfaf71608c12d8a402bd670d4/> mild refactor of paths module to waste less on unix
+ Previously it might have performed find-and-replace on unix paths even
+ though they wouldn't have changed afterwards, yet costing an allocation.
+
+ There is also the realization that it should go into its own crate to have
+ neater import paths and more convenience.
+ - <csr-id-8945d95f7fa88562d37ff67ac6e38bead73dd2df/> `interrupt::Iter`, rename `interrupt::Iter` -> `interrupt::IterWithError`
+
+### Chore (BREAKING)
+
+ - <csr-id-5bf0034fb3918e57562b7089ceba83d63a1854bf/> upgrade to prodash v23
+
+### Changed (BREAKING)
+
+ - <csr-id-38446dc8824afef30ef121598de3451d13b9262c/> remove `fs-jwalk-single-threaded` in favor of `fs-walkdir-parallel`.
+ This way, `jwalk` and the dependencies (and troubles) it brings have to
+ be opted in, but also allow other users to actually opt out while
+ allowing the `parallel` feature to be in effect.
+
+ In other words, previously the `parallel` feature conflated `jwalk`
+ dependencies into the tree, which isn't the case anymore.
+ - <csr-id-89a41bf2b37db29b9983b4e5492cfd67ed490b23/> remove local-time-support feature toggle.
+ We treat local time as default feature without a lot of fuzz, and
+ will eventually document that definitive support needs a compile
+ time switch in the compiler (`--cfg unsound_local_offset` or something).
+
+ One day it will perish. Failure is possible anyway and we will write
+ code to deal with it while minimizing the amount of system time
+ fetches when asking for the current local time.
+ - <csr-id-90611ce1527618bcc738440bfc1ccc7a45319974/> remove `path` module in favor of `git-path` crate
+ - <csr-id-61e5cfece4d8f405e35fc1957b00ce1da7526c26/> renamed `progress::Read::reader` -> `progress::Read::inner`
+ - <csr-id-e7526b2a7b51cbac4018e1ab3b623a85987fadc2/> parallel utilities now use `Send + Clone` insted of `Send + Sync`
+ This helps to assure that thread-local computations always work with the
+ kind of types we provide. The ones that are carrying out actions are
+ notably not `Sync` anymore.
+
+ We cater to that by defining our bounds accordingly, but for those
+ who want to use other utilities that need Sync, using types like
+ `Repository` and `thread_local!()` is the only way to make this
+ work.
+
+### Other
+
+ - <csr-id-ab6f98b905f13ed2a7c0c483f34fab63141fbc5b/> try-join with static typing works, but…
+ …seems like a lot of effort. Probably not worth continuing here
+
+### Bug Fixes
+
+ - <csr-id-234cd10ca55482ce1a840ce3244308d249895bcc/> Assure std::io::copy() doesn't hang when we cause an interrupt
+ The user can ask for interruptions which previously used the
+ error kind Interrupted. This however has special meaning and
+ usually means to retry.
+
+### Documentation
+
+ - <csr-id-39ed9eda62b7718d5109135e5ad406fb1fe2978c/> fix typos
+
+### Chore
+
+ - <csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/> uniformize deny attributes
+ - <csr-id-361892ca15aa648802f6701ab6a5a30aedde3449/> update sha-1 dependency to 0.10
+
+### New Features
+
+ - <csr-id-a3bd14a7753716e7ad67cd56d24eee1fa099a6fd/> re-export `prodash::progress::(Task|Value)` directly under `progress`
+ This is in addition to the `progress` re-export which allows everything
+ but yields less optimal import paths.
+ - <csr-id-426057247a80821b3da22b4ae5d67bda89ce0631/> re-export `prodash` in `progress` module.
+ That way one can access all types even if they are not re-exported.
+ - <csr-id-c4a7634b0b29c74625e183953e59c65987e9d66c/> export `prodash::progress::Id` in the `progress` module for convenience.
+ - <csr-id-25ad372bf500b851105f53b10369b5a689ba167e/> zlib::inflate::Error can now represent zlib status codes that represent failure.
+ - <csr-id-6d530a1dc77f0f4ac00622a2fd47c7bdb731a77a/> name spawned threads
+ That way it's a bit more obvious what's happening when the CPU goes
+ up in flames.
+ - <csr-id-c8835c6edae784c9ffcb69a674c0a6545dbb2af3/> upgrade to `prodash 21.1` and add `Ids` to all progress instances.
+ That way callers can identify progress they are interested in, say, for
+ selective visualizations.
+ - <csr-id-9076ce33ec167e425a0163d3e40a81a3fd0db6cd/> `fs::Snapshot` can `Clone` if `T` can `Clone`.
+ - <csr-id-a7c11d2cb5f88a4ff322d9a9848459062790d8b3/> perfect granularity for threads processing with `in_parallel_with_slice()`
+ - <csr-id-ff1db66f2dad3afc8bc77610006bca9fea5947d2/> add `progress::Step|StepShared` as types of `prodash`
+ This may help to use the `Progress::counter()` method as part of method
+ signatures, being an `Option<progress::StepShared>`.
+ - <csr-id-cfe46b502afc3ecb312849ddbd7748007d432cd1/> add zlib-ng feature to allow linking against system libz-ng
+ Allow to use zlib-ng (zlib-ng-sys) with native API (no compat mode)
+ that can co-exist with system libz (loaded by e.g. libcurl).
+ This is used in gitoxide package on Alpine Linux.
+ - <csr-id-b1c40b0364ef092cd52d03b34f491b254816b18d/> use docsrs feature in code to show what is feature-gated automatically on docs.rs
+ - <csr-id-517677147f1c17304c62cf97a1dd09f232ebf5db/> pass --cfg docsrs when compiling for https://docs.rs
+ - <csr-id-f498d35baba52e40ecd47381e87c1ce49cf13285/> add `fs-jwalk-single-threaded` feature to specifically decouple `jwalk` from rayon
+ It has been an issue in https://github.com/starship/starship/issues/4251
+ apparently and rayon interactions can be difficult.
+ - <csr-id-7f199f0e5246809efde9880110093fbd11a4f8fe/> `fs::Snapshot` to on-demand reload shared resources.
+ - <csr-id-c76fde7de278b49ded13b655d5345e4eb8c1b134/> initialize `Time` from `now_utc` and `now_local`
+ Localtime support depends on some other factors now, but that
+ will only get better over time.
+
+ We might have to document `unsound_local_time` at some point.
+ - <csr-id-e4d6685064ad2b433f8acd3a74b320bf0169a994/> Add `git_config::values::Path` for a typesafe git path
+ Add a `Path` type to the `git_config::values` which
+ can be interpolated according to gits own path interpolation
+ rules.
+ - <csr-id-3c8581fc294c65c9eb42698969fe3263135a864e/> add new 'path' module for all path-related conversions
+ It's meant to unify all path and byte related handling to help assuring
+ encoding is handled correctly or at least similarly everywhere.
+ - <csr-id-15ff212b17087de93f259e366f4e4b821cfbc28e/> in-manifest and in-lib documentation of feature toggles
+ - <csr-id-cb7e4e784d615f9fa3d6fb9c36240f0592403358/> Add InOrderIter to 'parallel' module
+ This iterator makes possible identifies results using a sequence id
+ and returns only consecutive items.
+
+ Use it to collect unordered results produced by threads.
+ It's advantage to collecting yourself and sorting is the potential
+ for a smaller memory footprint of in-flight results, one doesn't
+ have to collect them all for ordering, necessarily.
+ - <csr-id-ca095ed881db2a8f06a6b067dbaac17e923b0945/> Make a scope-like abstraction available
+ This allows more delicate threading control like is required for the
+ index.
+ - <csr-id-b8400ed80543d67a5895c975ba9b1fc28427411c/> decoding of variable int numbers.
+ It's here only so that we can share the code across crates, for now
+ without any feature toggles.
+ - <csr-id-0a749a22057b5513a8cefa0e26b0a9a268c769d3/> Add `progress::Write` to automatically pass bytes written to a progress instance
+ - <csr-id-7e95d8ab29051ffc892f2dcbaf5369e8c7e7b294/> add threading primitives with feature toggle
+ If the `threading` feature is set, the `threading` module will contain thread-safe primitives
+ for shared ownership and mutation, otherwise these will be their single threaded counterparts.
+
+ This way, single-threaded applications don't have to pay for threaded primitives.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 509 commits contributed to the release over the course of 962 calendar days.
+ - 38 commits were understood as [conventional](https://www.conventionalcommits.org).
+ - 21 unique issues were worked on: [#198](https://github.com/Byron/gitoxide/issues/198), [#222](https://github.com/Byron/gitoxide/issues/222), [#259](https://github.com/Byron/gitoxide/issues/259), [#263](https://github.com/Byron/gitoxide/issues/263), [#266](https://github.com/Byron/gitoxide/issues/266), [#279](https://github.com/Byron/gitoxide/issues/279), [#287](https://github.com/Byron/gitoxide/issues/287), [#293](https://github.com/Byron/gitoxide/issues/293), [#298](https://github.com/Byron/gitoxide/issues/298), [#301](https://github.com/Byron/gitoxide/issues/301), [#329](https://github.com/Byron/gitoxide/issues/329), [#331](https://github.com/Byron/gitoxide/issues/331), [#333](https://github.com/Byron/gitoxide/issues/333), [#366](https://github.com/Byron/gitoxide/issues/366), [#427](https://github.com/Byron/gitoxide/issues/427), [#450](https://github.com/Byron/gitoxide/issues/450), [#470](https://github.com/Byron/gitoxide/issues/470), [#503](https://github.com/Byron/gitoxide/issues/503), [#524](https://github.com/Byron/gitoxide/issues/524), [#63](https://github.com/Byron/gitoxide/issues/63), [#691](https://github.com/Byron/gitoxide/issues/691)
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **[#198](https://github.com/Byron/gitoxide/issues/198)**
+ - Handle changelogs with upcoming version section if they were left for editing ([`0f5f47d`](https://github.com/Byron/gitoxide/commit/0f5f47da4662b596cbbbd9c0d83e135e2cc52c11))
+ - Deduplicate conventional message ids ([`e695eda`](https://github.com/Byron/gitoxide/commit/e695eda8cd183f703d9a3e59b7c3c7fa496ea1d2))
+ - Regenerate all changelogs to get links ([`0c81769`](https://github.com/Byron/gitoxide/commit/0c817690bd444f52bed2936b2b451cafd87dde92))
+ - Mention actual issues that where worked on ([`a517e39`](https://github.com/Byron/gitoxide/commit/a517e39a81145b331f6c7a6cc2fc22e25daf42e2))
+ - Allow 'refactor' and 'other' in conventional messages if they have breaking changes ([`4eebaac`](https://github.com/Byron/gitoxide/commit/4eebaac669e590beed112b622752997c64772ef1))
+ - New changelogs for actor and features crates ([`e0d437c`](https://github.com/Byron/gitoxide/commit/e0d437c4cfa06e0792609f41ed5876c390634921))
+ * **[#222](https://github.com/Byron/gitoxide/issues/222)**
+ - Update changelogs prior to release ([`9a493d0`](https://github.com/Byron/gitoxide/commit/9a493d0651b0b6d71cf230dc510a658be7f8cb19))
+ - Stabilize changelogs ([`920e832`](https://github.com/Byron/gitoxide/commit/920e83219911df1c440d3fe42fd5ec3a295b0bb8))
+ - Update changelogs prior to release ([`b3e2252`](https://github.com/Byron/gitoxide/commit/b3e2252f7461a003d9a4612da60ba931dd8c0bef))
+ * **[#259](https://github.com/Byron/gitoxide/issues/259)**
+ - Unify trait bounds for parallel code: prefer Clone over Sync ([`c805d0b`](https://github.com/Byron/gitoxide/commit/c805d0b231cf4d2f51dae7705bfbbc6562f86c32))
+ - Remove trait bounds to allow single-threaded applications to exist ([`3c790e0`](https://github.com/Byron/gitoxide/commit/3c790e01de0dbd3ffa2683d5cf060723d11d64a5))
+ * **[#263](https://github.com/Byron/gitoxide/issues/263)**
+ - Make it possible to return read guards with packed buffers ([`f5c3c8f`](https://github.com/Byron/gitoxide/commit/f5c3c8f7309bf53b9e53f786e75931d701a8585c))
+ - Parallel utilities now use `Send + Clone` insted of `Send + Sync` ([`e7526b2`](https://github.com/Byron/gitoxide/commit/e7526b2a7b51cbac4018e1ab3b623a85987fadc2))
+ - A mad attempt to use thread-local everywhere and avoid Sync… ([`0af5077`](https://github.com/Byron/gitoxide/commit/0af5077e1f028c1c69bbdc098bb567e486282c37))
+ - Add threading primitives with feature toggle ([`7e95d8a`](https://github.com/Byron/gitoxide/commit/7e95d8ab29051ffc892f2dcbaf5369e8c7e7b294))
+ * **[#266](https://github.com/Byron/gitoxide/issues/266)**
+ - Update sha-1 dependency to 0.10 ([`361892c`](https://github.com/Byron/gitoxide/commit/361892ca15aa648802f6701ab6a5a30aedde3449))
+ - Remove slow/unnecessary threading utilities ([`269b7ef`](https://github.com/Byron/gitoxide/commit/269b7efc47bb1d6380b2059f63bd0c53fcd285de))
+ * **[#279](https://github.com/Byron/gitoxide/issues/279)**
+ - Add `progress::Write` to automatically pass bytes written to a progress instance ([`0a749a2`](https://github.com/Byron/gitoxide/commit/0a749a22057b5513a8cefa0e26b0a9a268c769d3))
+ - Renamed `progress::Read::reader` -> `progress::Read::inner` ([`61e5cfe`](https://github.com/Byron/gitoxide/commit/61e5cfece4d8f405e35fc1957b00ce1da7526c26))
+ - Adjust to changes in git-hash and git-pack ([`0cae25b`](https://github.com/Byron/gitoxide/commit/0cae25b1bb3c902ec323f17a1d9743e42fe213d0))
+ * **[#287](https://github.com/Byron/gitoxide/issues/287)**
+ - Upgrade to prodash 17 ([`47860b7`](https://github.com/Byron/gitoxide/commit/47860b7e2769260cfb8522ae455c491605093423))
+ * **[#293](https://github.com/Byron/gitoxide/issues/293)**
+ - Prepare changelogs for git-index and dependencies ([`f54bf4b`](https://github.com/Byron/gitoxide/commit/f54bf4bde92b892b6d425987a6a37e10319c4635))
+ - Fix docs ([`3f89b63`](https://github.com/Byron/gitoxide/commit/3f89b6336e79bc12bc31d40b74221e79a72d2b36))
+ - Fix build ([`e3977fe`](https://github.com/Byron/gitoxide/commit/e3977fe033550bfd3297cdd674934e40476aa38b))
+ - Use InOrderIter from git-features ([`7721b5f`](https://github.com/Byron/gitoxide/commit/7721b5fc7cba86d785e0936fdfab2ea41163219f))
+ - Add InOrderIter to 'parallel' module ([`cb7e4e7`](https://github.com/Byron/gitoxide/commit/cb7e4e784d615f9fa3d6fb9c36240f0592403358))
+ - Make a scope-like abstraction available ([`ca095ed`](https://github.com/Byron/gitoxide/commit/ca095ed881db2a8f06a6b067dbaac17e923b0945))
+ - Single and multi-threaded index tests ([`a22cb0f`](https://github.com/Byron/gitoxide/commit/a22cb0f1ead9a2f32e43eb2fb378281e592a4ed3))
+ - Decoding of variable int numbers. ([`b8400ed`](https://github.com/Byron/gitoxide/commit/b8400ed80543d67a5895c975ba9b1fc28427411c))
+ * **[#298](https://github.com/Byron/gitoxide/issues/298)**
+ - Enforce path conversion on windows gnu, it doesn't seem to like slashes ([`4d55a8f`](https://github.com/Byron/gitoxide/commit/4d55a8f99f2a0b7c0c4ed70a615b7e58b5bee04b))
+ - Use hash_hasher based hash state for better keys/less collisions ([`814de07`](https://github.com/Byron/gitoxide/commit/814de079f4226f42efa49ad334a348bce67184e4))
+ - Upgrade parking_lot and cargo_toml ([`f95c1a0`](https://github.com/Byron/gitoxide/commit/f95c1a0d9c19bcc6feb9b8739a09d86f9970a0e0))
+ * **[#301](https://github.com/Byron/gitoxide/issues/301)**
+ - Update changelogs prior to release ([`84cb256`](https://github.com/Byron/gitoxide/commit/84cb25614a5fcddff297c1713eba4efbb6ff1596))
+ - Remove `path` module in favor of `git-path` crate ([`90611ce`](https://github.com/Byron/gitoxide/commit/90611ce1527618bcc738440bfc1ccc7a45319974))
+ - Mild refactor of paths module to waste less on unix ([`d078d6e`](https://github.com/Byron/gitoxide/commit/d078d6ee76a80d1dfaf71608c12d8a402bd670d4))
+ - Refactor ([`8345b7c`](https://github.com/Byron/gitoxide/commit/8345b7caa0cc1cd8489e41822eea89da4c539e6d))
+ - More stable testing of perviously racy test for new parallelization mechanism ([`0b4b90f`](https://github.com/Byron/gitoxide/commit/0b4b90fa498d9e07a55b72af2f799da4cd2da81f))
+ - Salvage an alternative parallelization approach which might be good for index-creation ([`7e76796`](https://github.com/Byron/gitoxide/commit/7e76796d5c2956961bd998286bec05fca1ba8fc4))
+ - Refactor ([`f86eacc`](https://github.com/Byron/gitoxide/commit/f86eacc5cfaf6d88ead4f8dbd65989d32674c213))
+ - Use hopefully faster crossbeam channel to receive parallelized results ([`3b324b8`](https://github.com/Byron/gitoxide/commit/3b324b868d9d172038797f911eeebfcba8107865))
+ - Switch index checkout to chunk-based operation ([`e5f6943`](https://github.com/Byron/gitoxide/commit/e5f69433e4a6cc7866b666e0baccfa32efb92a7f))
+ - Add thread-count and chunk-size computation; interrupt capability ([`8cbe85d`](https://github.com/Byron/gitoxide/commit/8cbe85d135898826a91939726465a9e295c1e24b))
+ - `interrupt::Iter`, rename `interrupt::Iter` -> `interrupt::IterWithError` ([`8945d95`](https://github.com/Byron/gitoxide/commit/8945d95f7fa88562d37ff67ac6e38bead73dd2df))
+ - Fix `interrupt::Iter` ([`0f0d390`](https://github.com/Byron/gitoxide/commit/0f0d390c475044a75e5db4dcd831d755e74aa3e9))
+ * **[#329](https://github.com/Byron/gitoxide/issues/329)**
+ - In-manifest and in-lib documentation of feature toggles ([`15ff212`](https://github.com/Byron/gitoxide/commit/15ff212b17087de93f259e366f4e4b821cfbc28e))
+ * **[#331](https://github.com/Byron/gitoxide/issues/331)**
+ - Remove local-time-support feature toggle. ([`89a41bf`](https://github.com/Byron/gitoxide/commit/89a41bf2b37db29b9983b4e5492cfd67ed490b23))
+ - Initialize `Time` from `now_utc` and `now_local` ([`c76fde7`](https://github.com/Byron/gitoxide/commit/c76fde7de278b49ded13b655d5345e4eb8c1b134))
+ - A first sketch on how identity management could look like. ([`780f14f`](https://github.com/Byron/gitoxide/commit/780f14f5c270802e51cf039639c2fbdb5ac5a85e))
+ - Update changelog prior to release ([`1d07934`](https://github.com/Byron/gitoxide/commit/1d079346e789b0acc9a4bdf7577b21c1c37b6106))
+ - Remove Option return values in favor of Result ([`493dbae`](https://github.com/Byron/gitoxide/commit/493dbae434e8e4a939e90d03ec3f500744c0725a))
+ - Add `git_config::values::Path` for a typesafe git path ([`e4d6685`](https://github.com/Byron/gitoxide/commit/e4d6685064ad2b433f8acd3a74b320bf0169a994))
+ * **[#333](https://github.com/Byron/gitoxide/issues/333)**
+ - Use git_features::path everywhere where there is a path conversion ([`2e1437c`](https://github.com/Byron/gitoxide/commit/2e1437cb0b5dc77f2317881767f71eaf9b009ebf))
+ - Make real clear panics are only possible on windows ([`6b283dc`](https://github.com/Byron/gitoxide/commit/6b283dc7b9339fd65ea35f56eb29f121f571caf7))
+ - One usage of os_str_bytes down, along with some custom conversion code ([`1cc95ce`](https://github.com/Byron/gitoxide/commit/1cc95cefbd132a4277ec52c2147f7c81fea92d48))
+ - Gitoxide-core without os-str-bytes ([`909aa14`](https://github.com/Byron/gitoxide/commit/909aa1402c82c3128052023613a297b213716e3d))
+ - Remove os_str_bytes from git-pack ([`86f6e50`](https://github.com/Byron/gitoxide/commit/86f6e5054ea11b7aeb9c85321913de090f71e3a1))
+ - Don't use os_str_ext in git-features; adapt git-ref ([`9258b7b`](https://github.com/Byron/gitoxide/commit/9258b7baf0895593c13a152ff9e6f52e036cebe1))
+ - Add new 'path' module for all path-related conversions ([`3c8581f`](https://github.com/Byron/gitoxide/commit/3c8581fc294c65c9eb42698969fe3263135a864e))
+ * **[#366](https://github.com/Byron/gitoxide/issues/366)**
+ - The first possibly working version of loading a mailmap with multiple sources ([`98d745e`](https://github.com/Byron/gitoxide/commit/98d745e8080975a91cff1ce75e187258c851d3f4))
+ - Cleanup bstr usage to not accidentally pull in unicode ([`8ff53af`](https://github.com/Byron/gitoxide/commit/8ff53af9876a5e35bcfd076124ad776e1b6ff331))
+ * **[#427](https://github.com/Byron/gitoxide/issues/427)**
+ - Make fmt ([`4b320e7`](https://github.com/Byron/gitoxide/commit/4b320e773368ac5e8c38dd8a779ef3d6d2d024ec))
+ - Optimize some portions of the Snapshot code for speed. ([`711fd5c`](https://github.com/Byron/gitoxide/commit/711fd5c6c221440917fa68248e45d5278c780a9e))
+ - More convenient API for fs::Snapshots ([`561d2e7`](https://github.com/Byron/gitoxide/commit/561d2e746b1b82ac20f6f14b9c4e3910240075b4))
+ - `fs::Snapshot` to on-demand reload shared resources. ([`7f199f0`](https://github.com/Byron/gitoxide/commit/7f199f0e5246809efde9880110093fbd11a4f8fe))
+ - Use generalized reload-on-demand in `git-ref` ([`8d0cce7`](https://github.com/Byron/gitoxide/commit/8d0cce7d1521374d5199552fc69a417a957519bc))
+ - Now it's possible to update packed refs using the shared code ([`78222c2`](https://github.com/Byron/gitoxide/commit/78222c2e39aa24c84852e999448c042f2fd37db4))
+ - The first step towards using the generalized `ReloadIfChanged` in git-ref ([`e8de0ef`](https://github.com/Byron/gitoxide/commit/e8de0ef38db2f2d83cb277ed101464f23c0e98e4))
+ - Generalized port of packed-refs update logic for use in index ([`e3aff0c`](https://github.com/Byron/gitoxide/commit/e3aff0c2b83720e5745f3d7a8d0f571421a26d99))
+ - Turn on performance mode for sha-1 computation ([`44371a1`](https://github.com/Byron/gitoxide/commit/44371a10f464f32db346aa6b8309e983cfa20933))
+ * **[#450](https://github.com/Byron/gitoxide/issues/450)**
+ - Upgrade to `prodash` v21 ([`a0655dc`](https://github.com/Byron/gitoxide/commit/a0655dc7bc5dff388bc69a648e7f16b44fd1abd9))
+ - `fs::Snapshot` can `Clone` if `T` can `Clone`. ([`9076ce3`](https://github.com/Byron/gitoxide/commit/9076ce33ec167e425a0163d3e40a81a3fd0db6cd))
+ * **[#470](https://github.com/Byron/gitoxide/issues/470)**
+ - Update changelogs prior to release ([`caa7a1b`](https://github.com/Byron/gitoxide/commit/caa7a1bdef74d7d3166a7e38127a59f5ab3cfbdd))
+ - Working progress printing ([`67ec2c7`](https://github.com/Byron/gitoxide/commit/67ec2c7f9a4a6cefdf7148f5c7e48a79f201c4d2))
+ - First attempt to get progress information from stat worker. ([`0947c70`](https://github.com/Byron/gitoxide/commit/0947c703f9cecc31ceba101565e6ecafb00adb08))
+ - Upgrade to prodash 20.1 for `Progress::counter()` feature ([`0ac4a2c`](https://github.com/Byron/gitoxide/commit/0ac4a2c514aeb94d8e90ce28ae7a0e0350c21ab2))
+ * **[#503](https://github.com/Byron/gitoxide/issues/503)**
+ - Prepare changelog ([`3c99e7f`](https://github.com/Byron/gitoxide/commit/3c99e7f02ada72a171856ffc5b870da83fffc703))
+ * **[#524](https://github.com/Byron/gitoxide/issues/524)**
+ - Prepare changelogs prior to release ([`6446b39`](https://github.com/Byron/gitoxide/commit/6446b395d5926565ef899b0c923f35468ccf1921))
+ * **[#63](https://github.com/Byron/gitoxide/issues/63)**
+ - Git-protocol uses `oid` type ([`3930a6f`](https://github.com/Byron/gitoxide/commit/3930a6ff508f5bb2249fb2c2f21e00b74fecda22))
+ - Make ObjectId/oid happen! ([`ca78d15`](https://github.com/Byron/gitoxide/commit/ca78d15373ec988d909be8f240baefe75555e077))
+ - Move git-hash::owned::Id into git-hash::Id ([`fdbe704`](https://github.com/Byron/gitoxide/commit/fdbe704b6c9ace2b8f629f681a0580b24749a238))
+ - Rename `git_hash::*::Digest` to `Id` ([`188d90a`](https://github.com/Byron/gitoxide/commit/188d90ad463d342d715af701b03f0ed392c977fc))
+ * **[#691](https://github.com/Byron/gitoxide/issues/691)**
+ - Set `rust-version` to 1.64 ([`55066ce`](https://github.com/Byron/gitoxide/commit/55066ce5fd71209abb5d84da2998b903504584bb))
+ * **Uncategorized**
+ - Release gix-features v0.26.4, gix-actor v0.17.1, gix-glob v0.5.3, gix-path v0.7.1, gix-quote v0.4.1, gix-attributes v0.8.2, gix-config-value v0.10.1, gix-tempfile v3.0.2, gix-lock v3.0.2, gix-validate v0.7.2, gix-object v0.26.1, gix-ref v0.24.0, gix-sec v0.6.2, gix-config v0.16.1, gix-command v0.2.3, gix-prompt v0.3.2, gix-url v0.13.2, gix-credentials v0.9.1, gix-diff v0.26.1, gix-discover v0.13.0, gix-hashtable v0.1.1, gix-bitmap v0.2.1, gix-traverse v0.22.1, gix-index v0.12.3, gix-mailmap v0.9.2, gix-chunk v0.4.1, gix-pack v0.30.2, gix-odb v0.40.2, gix-packetline v0.14.2, gix-transport v0.25.4, gix-protocol v0.26.3, gix-revision v0.10.3, gix-refspec v0.7.2, gix-worktree v0.12.2, gix v0.36.0 ([`6efd0d3`](https://github.com/Byron/gitoxide/commit/6efd0d31fbeca31ab7319aa2ac97bb31dc4ce055))
+ - Release gix-date v0.4.2, gix-hash v0.10.2, gix-features v0.26.4, gix-actor v0.17.1, gix-glob v0.5.3, gix-path v0.7.1, gix-quote v0.4.1, gix-attributes v0.8.2, gix-config-value v0.10.1, gix-tempfile v3.0.2, gix-lock v3.0.2, gix-validate v0.7.2, gix-object v0.26.1, gix-ref v0.24.0, gix-sec v0.6.2, gix-config v0.16.1, gix-command v0.2.3, gix-prompt v0.3.2, gix-url v0.13.2, gix-credentials v0.9.1, gix-diff v0.26.1, gix-discover v0.13.0, gix-hashtable v0.1.1, gix-bitmap v0.2.1, gix-traverse v0.22.1, gix-index v0.12.3, gix-mailmap v0.9.2, gix-chunk v0.4.1, gix-pack v0.30.2, gix-odb v0.40.2, gix-packetline v0.14.2, gix-transport v0.25.4, gix-protocol v0.26.3, gix-revision v0.10.3, gix-refspec v0.7.2, gix-worktree v0.12.2, gix v0.36.0 ([`6ccc88a`](https://github.com/Byron/gitoxide/commit/6ccc88a8e4a56973b1a358cf72dc012ee3c75d56))
+ - Merge branch 'rename-crates' into inform-about-gix-rename ([`c9275b9`](https://github.com/Byron/gitoxide/commit/c9275b99ea43949306d93775d9d78c98fb86cfb1))
+ - Rename `git-testtools` to `gix-testtools` ([`b65c33d`](https://github.com/Byron/gitoxide/commit/b65c33d256cfed65d11adeff41132e3e58754089))
+ - Adjust to renaming of `git-pack` to `gix-pack` ([`1ee81ad`](https://github.com/Byron/gitoxide/commit/1ee81ad310285ee4aa118118a2be3810dbace574))
+ - Adjust to renaming of `git-odb` to `gix-odb` ([`476e2ad`](https://github.com/Byron/gitoxide/commit/476e2ad1a64e9e3f0d7c8651d5bcbee36cd78241))
+ - Adjust to renaming of `git-index` to `gix-index` ([`86db5e0`](https://github.com/Byron/gitoxide/commit/86db5e09fc58ce66b252dc13b8d7e2c48e4d5062))
+ - Adjust to renaming of `git-diff` to `gix-diff` ([`49a163e`](https://github.com/Byron/gitoxide/commit/49a163ec8b18f0e5fcd05a315de16d5d8be7650e))
+ - Adjust to renaming of `git-commitgraph` to `gix-commitgraph` ([`f1dd0a3`](https://github.com/Byron/gitoxide/commit/f1dd0a3366e31259af029da73228e8af2f414244))
+ - Adjust to renaming of `git-mailmap` to `gix-mailmap` ([`2e28c56`](https://github.com/Byron/gitoxide/commit/2e28c56bb9f70de6f97439818118d3a25859698f))
+ - Adjust to renaming of `git-discover` to `gix-discover` ([`53adfe1`](https://github.com/Byron/gitoxide/commit/53adfe1c34e9ea3b27067a97b5e7ac80b351c441))
+ - Adjust to renaming of `git-chunk` to `gix-chunk` ([`59194e3`](https://github.com/Byron/gitoxide/commit/59194e3a07853eae0624ebc4907478d1de4f7599))
+ - Adjust to renaming of `git-bitmap` to `gix-bitmap` ([`75f2a07`](https://github.com/Byron/gitoxide/commit/75f2a079b17489f62bc43e1f1d932307375c4f9d))
+ - Adjust to renaming for `git-protocol` to `gix-protocol` ([`823795a`](https://github.com/Byron/gitoxide/commit/823795addea3810243cab7936cd8ec0137cbc224))
+ - Adjust to renaming of `git-refspec` to `gix-refspec` ([`c958802`](https://github.com/Byron/gitoxide/commit/c9588020561577736faa065e7e5b5bb486ca8fe1))
+ - Adjust to renaming of `git-revision` to `gix-revision` ([`ee0ee84`](https://github.com/Byron/gitoxide/commit/ee0ee84607c2ffe11ee75f27a31903db68afed02))
+ - Adjust to renaming of `git-transport` to `gix-transport` ([`b2ccf71`](https://github.com/Byron/gitoxide/commit/b2ccf716dc4425bb96651d4d58806a3cc2da219e))
+ - Adjust to renaming of `git-credentials` to `gix-credentials` ([`6b18abc`](https://github.com/Byron/gitoxide/commit/6b18abcf2856f02ab938d535a65e51ac282bf94a))
+ - Adjust to renaming of `git-prompt` to `gix-prompt` ([`6a4654e`](https://github.com/Byron/gitoxide/commit/6a4654e0d10ab773dd219cb4b731c0fc1471c36d))
+ - Adjust to renaming of `git-command` to `gix-command` ([`d26b8e0`](https://github.com/Byron/gitoxide/commit/d26b8e046496894ae06b0bbfdba77196976cd975))
+ - Adjust to renaming of `git-packetline` to `gix-packetline` ([`5cbd22c`](https://github.com/Byron/gitoxide/commit/5cbd22cf42efb760058561c6c3bbcd4dab8c8be1))
+ - Adjust to renaming of `git-worktree` to `gix-worktree` ([`73a1282`](https://github.com/Byron/gitoxide/commit/73a12821b3d9b66ec1714d07dd27eb7a73e3a544))
+ - Adjust to renamining of `git-hashtable` to `gix-hashtable` ([`26a0c98`](https://github.com/Byron/gitoxide/commit/26a0c98d0a389b03e3dc7bfc758b37155e285244))
+ - Adjust to renamining of `git-worktree` to `gix-worktree` ([`108bb1a`](https://github.com/Byron/gitoxide/commit/108bb1a634f4828853fb590e9fc125f79441dd38))
+ - Adjust to renaming of `git-url` to `gix-url` ([`b50817a`](https://github.com/Byron/gitoxide/commit/b50817aadb143e19f61f64e19b19ec1107d980c6))
+ - Adjust to renaming of `git-date` to `gix-date` ([`9a79ff2`](https://github.com/Byron/gitoxide/commit/9a79ff2d5cc74c1efad9f41e21095ae498cce00b))
+ - Adjust to renamining of `git-attributes` to `gix-attributes` ([`4a8b3b8`](https://github.com/Byron/gitoxide/commit/4a8b3b812ac26f2a2aee8ce8ca81591273383c84))
+ - Adjust to renaminig of `git-quote` to `gix-quote` ([`648025b`](https://github.com/Byron/gitoxide/commit/648025b7ca94411fdd0d90c53e5faede5fde6c8d))
+ - Adjust to renaming of `git-config` to `gix-config` ([`3a861c8`](https://github.com/Byron/gitoxide/commit/3a861c8f049f6502d3bcbdac752659aa1aeda46a))
+ - Adjust to renaming of `git-ref` to `gix-ref` ([`1f5f695`](https://github.com/Byron/gitoxide/commit/1f5f695407b034377d94b172465ff573562b3fc3))
+ - Adjust to renaming of `git-lock` to `gix-lock` ([`2028e78`](https://github.com/Byron/gitoxide/commit/2028e7884ae1821edeec81612f501e88e4722b17))
+ - Adjust to renaming of `git-tempfile` to `gix-tempfile` ([`b6cc3eb`](https://github.com/Byron/gitoxide/commit/b6cc3ebb5137084a6327af16a7d9364d8f092cc9))
+ - Adjust to renaming of `git-object` to `gix-object` ([`fc86a1e`](https://github.com/Byron/gitoxide/commit/fc86a1e710ad7bf076c25cc6f028ddcf1a5a4311))
+ - Adjust to renaming of `git-actor` to `gix-actor` ([`4dc9b44`](https://github.com/Byron/gitoxide/commit/4dc9b44dc52f2486ffa2040585c6897c1bf55df4))
+ - Adjust to renaming of `git-validate` to `gix-validate` ([`5e40ad0`](https://github.com/Byron/gitoxide/commit/5e40ad078af3d08cbc2ca81ce755c0ed8a065b4f))
+ - Adjust to renaming of `git-hash` to `gix-hash` ([`4a9d025`](https://github.com/Byron/gitoxide/commit/4a9d0257110c3efa61d08c8457c4545b200226d1))
+ - Adjust to renaming of `git-features` to `gix-features` ([`e2dd68a`](https://github.com/Byron/gitoxide/commit/e2dd68a417aad229e194ff20dbbfd77668096ec6))
+ - Rename `git-features` to `gix-features` ([`85f7e1a`](https://github.com/Byron/gitoxide/commit/85f7e1a97c936f7cbebfbb3b2952f965601a7cbb))
+ - Adjust to renaming of `git-glob` to `gix-glob` ([`35b2a3a`](https://github.com/Byron/gitoxide/commit/35b2a3acbc8f2a03f151bc0a3863163844e0ca86))
+ - Adjust to renaming of `git-sec` to `gix-sec` ([`eabbb92`](https://github.com/Byron/gitoxide/commit/eabbb923bd5a32fc80fa80f96cfdc2ab7bb2ed17))
+ - Adapt to renaming of `git-path` to `gix-path` ([`d3bbcfc`](https://github.com/Byron/gitoxide/commit/d3bbcfccad80fc44ea8e7bf819f23adaca06ba2d))
+ - Adjust to rename of `git-config-value` to `gix-config-value` ([`622b3e1`](https://github.com/Byron/gitoxide/commit/622b3e1d0bffa0f8db73697960f9712024fac430))
+ - Release git-features v0.26.4 ([`109f434`](https://github.com/Byron/gitoxide/commit/109f434e66559a791d541f86876ded8df10766f1))
+ - Re-export `prodash::progress::(Task|Value)` directly under `progress` ([`a3bd14a`](https://github.com/Byron/gitoxide/commit/a3bd14a7753716e7ad67cd56d24eee1fa099a6fd))
+ - Release git-features v0.26.3 ([`1ecfb7f`](https://github.com/Byron/gitoxide/commit/1ecfb7f8bfb24432690d8f31367488f2e59a642a))
+ - Re-export `prodash` in `progress` module. ([`4260572`](https://github.com/Byron/gitoxide/commit/426057247a80821b3da22b4ae5d67bda89ce0631))
+ - Release git-date v0.4.2, git-hash v0.10.2, git-features v0.26.2, git-actor v0.17.1, git-glob v0.5.3, git-path v0.7.1, git-quote v0.4.1, git-attributes v0.8.2, git-config-value v0.10.1, git-tempfile v3.0.2, git-lock v3.0.2, git-validate v0.7.2, git-object v0.26.1, git-ref v0.24.0, git-sec v0.6.2, git-config v0.16.0, git-command v0.2.3, git-prompt v0.3.2, git-url v0.13.2, git-credentials v0.9.1, git-diff v0.26.1, git-discover v0.13.0, git-hashtable v0.1.1, git-bitmap v0.2.1, git-traverse v0.22.1, git-index v0.12.3, git-mailmap v0.9.2, git-chunk v0.4.1, git-pack v0.30.2, git-odb v0.40.2, git-packetline v0.14.2, git-transport v0.25.4, git-protocol v0.26.3, git-revision v0.10.2, git-refspec v0.7.2, git-worktree v0.12.2, git-repository v0.34.0, safety bump 3 crates ([`c196d20`](https://github.com/Byron/gitoxide/commit/c196d206d57a310b1ce974a1cf0e7e6d6db5c4d6))
+ - Prepare changelogs prior to release ([`7c846d2`](https://github.com/Byron/gitoxide/commit/7c846d2102dc767366771925212712ef8cc9bf07))
+ - Merge branch 'Lioness100/main' ([`1e544e8`](https://github.com/Byron/gitoxide/commit/1e544e82455bf9ecb5e3c2146280eaf7ecd81f16))
+ - Fix typos ([`39ed9ed`](https://github.com/Byron/gitoxide/commit/39ed9eda62b7718d5109135e5ad406fb1fe2978c))
+ - Make fmt ([`e22080e`](https://github.com/Byron/gitoxide/commit/e22080e4a29d0bad15a99d565a5e3e304a8743ec))
+ - Merge branch 'adjustments-for-cargo' ([`7bba270`](https://github.com/Byron/gitoxide/commit/7bba2709488b7eb999b8136dbab03af977241678))
+ - Export `prodash::progress::Id` in the `progress` module for convenience. ([`c4a7634`](https://github.com/Byron/gitoxide/commit/c4a7634b0b29c74625e183953e59c65987e9d66c))
+ - Release git-date v0.4.1, git-features v0.26.1, git-glob v0.5.2, git-attributes v0.8.1, git-tempfile v3.0.1, git-ref v0.23.1, git-sec v0.6.1, git-config v0.15.1, git-prompt v0.3.1, git-url v0.13.1, git-discover v0.12.1, git-index v0.12.2, git-mailmap v0.9.1, git-pack v0.30.1, git-odb v0.40.1, git-transport v0.25.3, git-protocol v0.26.2, git-revision v0.10.1, git-refspec v0.7.1, git-worktree v0.12.1, git-repository v0.33.0 ([`5b5b380`](https://github.com/Byron/gitoxide/commit/5b5b3809faa71c658db38b40dfc410224d08a367))
+ - Prepare changelogs prior to release ([`93bef97`](https://github.com/Byron/gitoxide/commit/93bef97b3c0c75d4bf7119fdd787516e1efc77bf))
+ - Merge branch 'patch-1' ([`b93f0c4`](https://github.com/Byron/gitoxide/commit/b93f0c49fc677b6c19aea332cbfc1445ce475375))
+ - Thanks clippy ([`9e04685`](https://github.com/Byron/gitoxide/commit/9e04685dd3f109bfb27663f9dc7c04102e660bf2))
+ - Release git-features v0.26.0, git-actor v0.16.0, git-attributes v0.8.0, git-object v0.25.0, git-ref v0.22.0, git-config v0.14.0, git-command v0.2.1, git-url v0.13.0, git-credentials v0.9.0, git-diff v0.25.0, git-discover v0.11.0, git-traverse v0.21.0, git-index v0.11.0, git-mailmap v0.8.0, git-pack v0.29.0, git-odb v0.39.0, git-transport v0.25.0, git-protocol v0.26.0, git-revision v0.9.0, git-refspec v0.6.0, git-worktree v0.11.0, git-repository v0.31.0, safety bump 24 crates ([`5ac9fbe`](https://github.com/Byron/gitoxide/commit/5ac9fbe265a5b61c533a2a6b3abfed2bdf7f89ad))
+ - Prepare changelogs prior to release ([`30d8ca1`](https://github.com/Byron/gitoxide/commit/30d8ca19284049dcfbb0de2698cafae1d1a16b0c))
+ - Make fmt ([`511ed00`](https://github.com/Byron/gitoxide/commit/511ed0000397a5b268530c8f5362e7d25b7c1594))
+ - Merge branch 'adjustments-for-cargo' ([`f8c562a`](https://github.com/Byron/gitoxide/commit/f8c562a559e6dc3377583cc7200585dad7c3d481))
+ - Upgrade to prodash v23 ([`5bf0034`](https://github.com/Byron/gitoxide/commit/5bf0034fb3918e57562b7089ceba83d63a1854bf))
+ - Release git-features v0.25.1, git-url v0.12.2, git-odb v0.38.1, git-transport v0.24.2, git-repository v0.30.2 ([`bb0a07b`](https://github.com/Byron/gitoxide/commit/bb0a07b5edd5f980989d1a92e74df7f183febe87))
+ - Merge branch 'loose-find-panic' ([`95cccdd`](https://github.com/Byron/gitoxide/commit/95cccddd3c181eb2a85b12823c27beb054adf5d8))
+ - Zlib::inflate::Error can now represent zlib status codes that represent failure. ([`25ad372`](https://github.com/Byron/gitoxide/commit/25ad372bf500b851105f53b10369b5a689ba167e))
+ - Release git-date v0.3.1, git-features v0.25.0, git-actor v0.15.0, git-glob v0.5.1, git-path v0.7.0, git-attributes v0.7.0, git-config-value v0.10.0, git-lock v3.0.1, git-validate v0.7.1, git-object v0.24.0, git-ref v0.21.0, git-sec v0.6.0, git-config v0.13.0, git-prompt v0.3.0, git-url v0.12.0, git-credentials v0.8.0, git-diff v0.24.0, git-discover v0.10.0, git-traverse v0.20.0, git-index v0.10.0, git-mailmap v0.7.0, git-pack v0.28.0, git-odb v0.38.0, git-packetline v0.14.1, git-transport v0.24.0, git-protocol v0.25.0, git-revision v0.8.0, git-refspec v0.5.0, git-worktree v0.10.0, git-repository v0.30.0, safety bump 26 crates ([`e6b9906`](https://github.com/Byron/gitoxide/commit/e6b9906c486b11057936da16ed6e0ec450a0fb83))
+ - Prepare chnagelogs prior to git-repository release ([`7114bbb`](https://github.com/Byron/gitoxide/commit/7114bbb6732aa8571d4ab74f28ed3e26e9fbe4d0))
+ - Merge branch 'main' into read-split-index ([`c57bdde`](https://github.com/Byron/gitoxide/commit/c57bdde6de37eca9672ea715962bbd02aa3eb055))
+ - Merge branch 'adjustments-for-cargo' ([`083909b`](https://github.com/Byron/gitoxide/commit/083909bc7eb902eeee2002034fdb6ed88280dc5c))
+ - Thanks clippy ([`f1160fb`](https://github.com/Byron/gitoxide/commit/f1160fb42acf59b37cbeda546a7079af3c9bc050))
+ - Add support for explicit non-parallel iteration. ([`0f27c67`](https://github.com/Byron/gitoxide/commit/0f27c67c92fc0bc23a6712b5c4c730ad6a0156bf))
+ - Merge branch 'adjustments-for-cargo' ([`70ccbb2`](https://github.com/Byron/gitoxide/commit/70ccbb21b1113bdeb20b52d274141a9fdb75f579))
+ - Upgrade to prodash v22 for API improvements ([`77ab98d`](https://github.com/Byron/gitoxide/commit/77ab98dd41c3849b674d8b3794ef29219ca1447d))
+ - Release git-hash v0.10.1, git-hashtable v0.1.0 ([`7717170`](https://github.com/Byron/gitoxide/commit/771717095d9a67b0625021eb0928828ab686e772))
+ - Merge branch 'main' into http-config ([`6b9632e`](https://github.com/Byron/gitoxide/commit/6b9632e16c416841ffff1b767ee7a6c89b421220))
+ - Release git-features v0.24.1, git-actor v0.14.1, git-index v0.9.1 ([`7893502`](https://github.com/Byron/gitoxide/commit/789350208efc9d5fc6f9bc4f113f77f9cb445156))
+ - Merge branch 'named-threads' ([`726dd87`](https://github.com/Byron/gitoxide/commit/726dd87b5db45c333ccad898338a1cacea9e3269))
+ - Name spawned threads ([`6d530a1`](https://github.com/Byron/gitoxide/commit/6d530a1dc77f0f4ac00622a2fd47c7bdb731a77a))
+ - Upgrade to `prodash 21.1` and add `Ids` to all progress instances. ([`c8835c6`](https://github.com/Byron/gitoxide/commit/c8835c6edae784c9ffcb69a674c0a6545dbb2af3))
+ - Merge branch 'main' into http-config ([`bcd9654`](https://github.com/Byron/gitoxide/commit/bcd9654e56169799eb706646da6ee1f4ef2021a9))
+ - Release git-hash v0.10.0, git-features v0.24.0, git-date v0.3.0, git-actor v0.14.0, git-glob v0.5.0, git-path v0.6.0, git-quote v0.4.0, git-attributes v0.6.0, git-config-value v0.9.0, git-tempfile v3.0.0, git-lock v3.0.0, git-validate v0.7.0, git-object v0.23.0, git-ref v0.20.0, git-sec v0.5.0, git-config v0.12.0, git-command v0.2.0, git-prompt v0.2.0, git-url v0.11.0, git-credentials v0.7.0, git-diff v0.23.0, git-discover v0.9.0, git-bitmap v0.2.0, git-traverse v0.19.0, git-index v0.9.0, git-mailmap v0.6.0, git-chunk v0.4.0, git-pack v0.27.0, git-odb v0.37.0, git-packetline v0.14.0, git-transport v0.23.0, git-protocol v0.24.0, git-revision v0.7.0, git-refspec v0.4.0, git-worktree v0.9.0, git-repository v0.29.0, git-commitgraph v0.11.0, gitoxide-core v0.21.0, gitoxide v0.19.0, safety bump 28 crates ([`b2c301e`](https://github.com/Byron/gitoxide/commit/b2c301ef131ffe1871314e19f387cf10a8d2ac16))
+ - Prepare changelogs prior to release ([`e4648f8`](https://github.com/Byron/gitoxide/commit/e4648f827c97e9d13636d1bbdc83dd63436e6e5c))
+ - Release git-features v0.23.1, git-glob v0.4.1, git-config-value v0.8.1, git-tempfile v2.0.6, git-object v0.22.1, git-ref v0.18.0, git-sec v0.4.2, git-config v0.10.0, git-prompt v0.1.1, git-url v0.10.1, git-credentials v0.6.1, git-diff v0.21.0, git-discover v0.7.0, git-index v0.7.0, git-pack v0.25.0, git-odb v0.35.0, git-transport v0.21.1, git-protocol v0.22.0, git-refspec v0.3.1, git-worktree v0.7.0, git-repository v0.26.0, git-commitgraph v0.10.0, gitoxide-core v0.19.0, gitoxide v0.17.0, safety bump 9 crates ([`d071583`](https://github.com/Byron/gitoxide/commit/d071583c5576fdf5f7717765ffed5681792aa81f))
+ - Prepare changelogs prior to release ([`423af90`](https://github.com/Byron/gitoxide/commit/423af90c8202d62dc1ea4a76a0df6421d1f0aa06))
+ - Merge branch 'main' into write-sparse-index ([`c4e6849`](https://github.com/Byron/gitoxide/commit/c4e68496c368611ebe17c6693d06c8147c28c717))
+ - Merge branch 'gix-clone' ([`def53b3`](https://github.com/Byron/gitoxide/commit/def53b36c3dec26fa78939ab0584fe4ff930909c))
+ - Thanks clippy ([`ad96233`](https://github.com/Byron/gitoxide/commit/ad96233e1aa77fb7d9185f653f3e9519128cf20f))
+ - Release git-hash v0.9.11, git-features v0.23.0, git-actor v0.13.0, git-attributes v0.5.0, git-object v0.22.0, git-ref v0.17.0, git-sec v0.4.1, git-config v0.9.0, git-url v0.10.0, git-credentials v0.6.0, git-diff v0.20.0, git-discover v0.6.0, git-traverse v0.18.0, git-index v0.6.0, git-mailmap v0.5.0, git-pack v0.24.0, git-odb v0.34.0, git-packetline v0.13.1, git-transport v0.21.0, git-protocol v0.21.0, git-revision v0.6.0, git-refspec v0.3.0, git-worktree v0.6.0, git-repository v0.25.0, safety bump 24 crates ([`104d922`](https://github.com/Byron/gitoxide/commit/104d922add61ab21c534c24ce8ed37cddf3e275a))
+ - Prepare changelogs for release ([`d232567`](https://github.com/Byron/gitoxide/commit/d23256701a95284857dc8d1cb37c7c94cada973c))
+ - Remove `fs-jwalk-single-threaded` in favor of `fs-walkdir-parallel`. ([`38446dc`](https://github.com/Byron/gitoxide/commit/38446dc8824afef30ef121598de3451d13b9262c))
+ - Make jwalk fully optional ([`3b29fc1`](https://github.com/Byron/gitoxide/commit/3b29fc18672c0176684c797a0f16f85d09369bf8))
+ - Merge branch 'main' into new-http-impl ([`702a161`](https://github.com/Byron/gitoxide/commit/702a161ef11fc959611bf44b70e9ffe04561c7ad))
+ - Merge branch 'main' into clone ([`acb0738`](https://github.com/Byron/gitoxide/commit/acb07382a9306d6962bea60e8977d83d021743f4))
+ - Merge branch 'delta-tree-parallelization' ([`cca2ad5`](https://github.com/Byron/gitoxide/commit/cca2ad5ee9483d7da968658e0a4d610dbc4ad4d6))
+ - Don't enforce Send bounds in serial version of `in_parallel_with_slice()` ([`dda661e`](https://github.com/Byron/gitoxide/commit/dda661e1b7cc0ace6cd9504233f20980e1e52387))
+ - Allow discarding the state which could otherwise be used for aggregation. ([`56792fb`](https://github.com/Byron/gitoxide/commit/56792fb53299d52073555c8646360ec0ae88c86d))
+ - Allow input for `in_parallel_with_slice` to be mutable. ([`e928bf7`](https://github.com/Byron/gitoxide/commit/e928bf7c699a7e48ad283c2cf7fd7479c37c70fc))
+ - Perfect granularity for threads processing with `in_parallel_with_slice()` ([`a7c11d2`](https://github.com/Byron/gitoxide/commit/a7c11d2cb5f88a4ff322d9a9848459062790d8b3))
+ - Add `progress::Step|StepShared` as types of `prodash` ([`ff1db66`](https://github.com/Byron/gitoxide/commit/ff1db66f2dad3afc8bc77610006bca9fea5947d2))
+ - Merge branch 'fix-git-features' ([`82fd251`](https://github.com/Byron/gitoxide/commit/82fd251ac80d07bc9da8a4d36e517aa35580d188))
+ - Merge branch 'diff' ([`25a7726`](https://github.com/Byron/gitoxide/commit/25a7726377fbe400ea3c4927d04e9dec99802b7b))
+ - Release git-hash v0.9.10, git-features v0.22.5, git-date v0.2.0, git-actor v0.12.0, git-glob v0.4.0, git-path v0.5.0, git-quote v0.3.0, git-attributes v0.4.0, git-config-value v0.8.0, git-tempfile v2.0.5, git-validate v0.6.0, git-object v0.21.0, git-ref v0.16.0, git-sec v0.4.0, git-config v0.8.0, git-discover v0.5.0, git-traverse v0.17.0, git-index v0.5.0, git-worktree v0.5.0, git-testtools v0.9.0, git-command v0.1.0, git-prompt v0.1.0, git-url v0.9.0, git-credentials v0.5.0, git-diff v0.19.0, git-mailmap v0.4.0, git-chunk v0.3.2, git-pack v0.23.0, git-odb v0.33.0, git-packetline v0.13.0, git-transport v0.20.0, git-protocol v0.20.0, git-revision v0.5.0, git-refspec v0.2.0, git-repository v0.24.0, git-commitgraph v0.9.0, gitoxide-core v0.18.0, gitoxide v0.16.0, safety bump 28 crates ([`29a043b`](https://github.com/Byron/gitoxide/commit/29a043be6808a3e9199a9b26bd076fe843afe4f4))
+ - Release git-features v0.22.6 ([`c9eda72`](https://github.com/Byron/gitoxide/commit/c9eda729d8f8bc266c7516c613d38acfb83a4743))
+ - Update changelog prior to release ([`ff80042`](https://github.com/Byron/gitoxide/commit/ff80042c9691e5dba5834c674174fdf6d3bdfe7d))
+ - Fix git-features docs build ([`e5963fe`](https://github.com/Byron/gitoxide/commit/e5963fea183d81db1fe502121b494146a58bd86e))
+ - Upgrade all dependencies, except for `windows` ([`2968181`](https://github.com/Byron/gitoxide/commit/29681819ffe53d3926d631dc482f71d6200cb549))
+ - Merge branch 'dep-upgrade' ([`59767b1`](https://github.com/Byron/gitoxide/commit/59767b1fc1d07b8a7a9333a719e3716746611bc4))
+ - Upgrade prodash and crosstermion to latest versions ([`ab7ee5b`](https://github.com/Byron/gitoxide/commit/ab7ee5b5d5c15771f431ada9c3b4f53e4be2afdd))
+ - Add zlib-ng feature to allow linking against system libz-ng ([`cfe46b5`](https://github.com/Byron/gitoxide/commit/cfe46b502afc3ecb312849ddbd7748007d432cd1))
+ - Merge branch 'main' into filter-refs-by-spec ([`9aa1d3d`](https://github.com/Byron/gitoxide/commit/9aa1d3dc46d4b1c76af257f573aff3aeef2d3fa8))
+ - Release git-features v0.22.4, git-url v0.8.0, safety bump 4 crates ([`1d4600a`](https://github.com/Byron/gitoxide/commit/1d4600ae51475c2e225f96c16c41e2c4a2b3f2aa))
+ - Merge branch 'main' into filter-refs-by-spec ([`1f6e5ab`](https://github.com/Byron/gitoxide/commit/1f6e5ab15f5fd8d23719b13e6aea59cd231ac0fe))
+ - Merge branch 'fix-522' ([`5869e9f`](https://github.com/Byron/gitoxide/commit/5869e9ff2508d5a93c07635277af8764fcb57713))
+ - Release git-hash v0.9.9 ([`da0716f`](https://github.com/Byron/gitoxide/commit/da0716f8c27b4f29cfff0e5ce7fcb3d7240f4aeb))
+ - Merge branch 'main' into index-from-tree ([`bc64b96`](https://github.com/Byron/gitoxide/commit/bc64b96a2ec781c72d1d4daad38aa7fb8b74f99b))
+ - Merge branch 'main' into filter-refs-by-spec ([`cef0b51`](https://github.com/Byron/gitoxide/commit/cef0b51ade2a3301fa09ede7a425aa1fe3527e78))
+ - Release git-features v0.22.3, git-revision v0.4.4 ([`c2660e2`](https://github.com/Byron/gitoxide/commit/c2660e2503323531ba02519eaa51124ee22fec51))
+ - Merge branch 'main' into filter-refs-by-spec ([`dbfa328`](https://github.com/Byron/gitoxide/commit/dbfa3282cf876596b250b2040c1ec0b761741796))
+ - Merge branch 'zlib-sys' ([`7b48297`](https://github.com/Byron/gitoxide/commit/7b482977a556d28f5d9759e1be33cdf3d85c8665))
+ - Restrict `sha1` `asm` to supported archs ([`b383fab`](https://github.com/Byron/gitoxide/commit/b383fabbe10868317be51b99cfdd9b0981816042))
+ - Add feature to link to traditional zlib for dynamic linking support ([`c954bbf`](https://github.com/Byron/gitoxide/commit/c954bbff60ba70a0f1680e3978dd1f8fc1e3a0e7))
+ - Merge branch 'main' into filter-refs-by-spec ([`cfa1440`](https://github.com/Byron/gitoxide/commit/cfa144031dbcac2707ab0cec012bc35e78f9c475))
+ - Release git-date v0.0.5, git-hash v0.9.8, git-features v0.22.2, git-actor v0.11.3, git-glob v0.3.2, git-quote v0.2.1, git-attributes v0.3.2, git-tempfile v2.0.4, git-lock v2.1.1, git-validate v0.5.5, git-object v0.20.2, git-ref v0.15.2, git-sec v0.3.1, git-config v0.7.0, git-credentials v0.4.0, git-diff v0.17.2, git-discover v0.4.1, git-bitmap v0.1.2, git-index v0.4.2, git-mailmap v0.3.2, git-chunk v0.3.1, git-traverse v0.16.2, git-pack v0.21.2, git-odb v0.31.2, git-packetline v0.12.7, git-url v0.7.2, git-transport v0.19.2, git-protocol v0.19.0, git-revision v0.4.2, git-refspec v0.1.0, git-worktree v0.4.2, git-repository v0.22.0, safety bump 4 crates ([`4974eca`](https://github.com/Byron/gitoxide/commit/4974eca96d525d1ee4f8cad79bb713af7a18bf9d))
+ - Merge branch 'main' into remote-ls-refs ([`e2ee3de`](https://github.com/Byron/gitoxide/commit/e2ee3ded97e5c449933712883535b30d151c7c78))
+ - Merge branch 'docsrs-show-features' ([`31c2351`](https://github.com/Byron/gitoxide/commit/31c235140cad212d16a56195763fbddd971d87ce))
+ - Use docsrs feature in code to show what is feature-gated automatically on docs.rs ([`b1c40b0`](https://github.com/Byron/gitoxide/commit/b1c40b0364ef092cd52d03b34f491b254816b18d))
+ - Uniformize deny attributes ([`f7f136d`](https://github.com/Byron/gitoxide/commit/f7f136dbe4f86e7dee1d54835c420ec07c96cd78))
+ - Pass --cfg docsrs when compiling for https://docs.rs ([`5176771`](https://github.com/Byron/gitoxide/commit/517677147f1c17304c62cf97a1dd09f232ebf5db))
+ - Merge branch 'main' into remote-ls-refs ([`bd5f3e8`](https://github.com/Byron/gitoxide/commit/bd5f3e8db7e0bb4abfb7b0f79f585ab82c3a14ab))
+ - Release git-hash v0.9.7, git-features v0.22.1 ([`232784a`](https://github.com/Byron/gitoxide/commit/232784a59ded3e8016e4257c7e146ad385cdd64a))
+ - Add `fs-jwalk-single-threaded` feature to specifically decouple `jwalk` from rayon ([`f498d35`](https://github.com/Byron/gitoxide/commit/f498d35baba52e40ecd47381e87c1ce49cf13285))
+ - Merge branch 'rev-parse-delegate' ([`2f506c7`](https://github.com/Byron/gitoxide/commit/2f506c7c2988477b0f97d272a9ac9ed47b236457))
+ - Thanks clippy! ([`c072dbb`](https://github.com/Byron/gitoxide/commit/c072dbb3e203e4a42843895b7d99404d900fdccd))
+ - Merge pull request #2 from SidneyDouw/main ([`ce885ad`](https://github.com/Byron/gitoxide/commit/ce885ad4c3324c09c83751c32e014f246c748766))
+ - Merge branch 'Byron:main' into main ([`9b9ea02`](https://github.com/Byron/gitoxide/commit/9b9ea0275f8ff5862f24cf5a4ca53bb1cd610709))
+ - Merge branch 'main' into rev-parse-delegate ([`6da8250`](https://github.com/Byron/gitoxide/commit/6da82507588d3bc849217c11d9a1d398b67f2ed6))
+ - Merge branch 'main' into pathspec ([`7b61506`](https://github.com/Byron/gitoxide/commit/7b615060712565f515515e35a3e8346278ad770c))
+ - Merge branch 'kianmeng-fix-typos' ([`4e7b343`](https://github.com/Byron/gitoxide/commit/4e7b34349c0a01ad8686bbb4eb987e9338259d9c))
+ - Fix typos ([`e9fcb70`](https://github.com/Byron/gitoxide/commit/e9fcb70e429edb2974afa3f58d181f3ef14c3da3))
+ - Release git-hash v0.9.6, git-features v0.22.0, git-date v0.0.2, git-actor v0.11.0, git-glob v0.3.1, git-path v0.4.0, git-attributes v0.3.0, git-tempfile v2.0.2, git-object v0.20.0, git-ref v0.15.0, git-sec v0.3.0, git-config v0.6.0, git-credentials v0.3.0, git-diff v0.17.0, git-discover v0.3.0, git-index v0.4.0, git-mailmap v0.3.0, git-traverse v0.16.0, git-pack v0.21.0, git-odb v0.31.0, git-url v0.7.0, git-transport v0.19.0, git-protocol v0.18.0, git-revision v0.3.0, git-worktree v0.4.0, git-repository v0.20.0, git-commitgraph v0.8.0, gitoxide-core v0.15.0, gitoxide v0.13.0, safety bump 22 crates ([`4737b1e`](https://github.com/Byron/gitoxide/commit/4737b1eea1d4c9a8d5a69fb63ecac5aa5d378ae5))
+ - Prepare changelog prior to release ([`3c50625`](https://github.com/Byron/gitoxide/commit/3c50625fa51350ec885b0f38ec9e92f9444df0f9))
+ - Merge branch 'config-cascade' ([`f144eaf`](https://github.com/Byron/gitoxide/commit/f144eaf5863ae5cac63103f0db51c35fcf03a948))
+ - Merge pull request #1 from Byron/main ([`085e76b`](https://github.com/Byron/gitoxide/commit/085e76b121291ed9bd324139105d2bd4117bedf8))
+ - Git-features' walkdir: 2.3.1 -> 2.3.2 ([`41dd754`](https://github.com/Byron/gitoxide/commit/41dd7545234e6d2637d2bca5bb6d4f6d8bfc8f57))
+ - Merge branch 'main' into pathspec ([`89ea12b`](https://github.com/Byron/gitoxide/commit/89ea12b558bcc056b892193ee8fb44b8664b5da4))
+ - Merge branch 'main' into cont_include_if ([`41ea8ba`](https://github.com/Byron/gitoxide/commit/41ea8ba78e74f5c988148367386a1f4f304cb951))
+ - Release git-date v0.0.1, git-hash v0.9.5, git-features v0.21.1, git-actor v0.10.1, git-path v0.2.0, git-attributes v0.2.0, git-ref v0.14.0, git-sec v0.2.0, git-config v0.5.0, git-credentials v0.2.0, git-discover v0.2.0, git-pack v0.20.0, git-odb v0.30.0, git-url v0.6.0, git-transport v0.18.0, git-protocol v0.17.0, git-revision v0.2.1, git-worktree v0.3.0, git-repository v0.19.0, safety bump 13 crates ([`a417177`](https://github.com/Byron/gitoxide/commit/a41717712578f590f04a33d27adaa63171f25267))
+ - Update changelogs prior to release ([`bb424f5`](https://github.com/Byron/gitoxide/commit/bb424f51068b8a8e762696890a55ab48900ab980))
+ - Assure we used most recent version of crossbeam-utils ([`033f0d3`](https://github.com/Byron/gitoxide/commit/033f0d3e0015b7eead6408c775d2101eb413ffbf))
+ - Merge branch 'main' into SidneyDouw-pathspec ([`a22b1d8`](https://github.com/Byron/gitoxide/commit/a22b1d88a21311d44509018729c3ef1936cf052a))
+ - Merge branch 'main' into git_includeif ([`598c853`](https://github.com/Byron/gitoxide/commit/598c853087fcf8f77299aa5b9803bcec705c0cd0))
+ - Release git-hash v0.9.4, git-features v0.21.0, git-actor v0.10.0, git-glob v0.3.0, git-path v0.1.1, git-attributes v0.1.0, git-sec v0.1.0, git-config v0.3.0, git-credentials v0.1.0, git-validate v0.5.4, git-object v0.19.0, git-diff v0.16.0, git-lock v2.1.0, git-ref v0.13.0, git-discover v0.1.0, git-index v0.3.0, git-mailmap v0.2.0, git-traverse v0.15.0, git-pack v0.19.0, git-odb v0.29.0, git-packetline v0.12.5, git-url v0.5.0, git-transport v0.17.0, git-protocol v0.16.0, git-revision v0.2.0, git-worktree v0.2.0, git-repository v0.17.0, safety bump 20 crates ([`654cf39`](https://github.com/Byron/gitoxide/commit/654cf39c92d5aa4c8d542a6cadf13d4acef6a78e))
+ - Merge branch 'main' into msrv-for-windows ([`7cb1972`](https://github.com/Byron/gitoxide/commit/7cb19729133325bdfacedf44cdc0500cbcf36684))
+ - Merge branch 'worktree-stack' ([`98da8ba`](https://github.com/Byron/gitoxide/commit/98da8ba52cef8ec27f705fcbc84773e5bacc4e10))
+ - Thanks clippy ([`380174f`](https://github.com/Byron/gitoxide/commit/380174f0ad9e60ccafcd4cfb24e244f106137964))
+ - Release git-features v0.20.0, git-config v0.2.0 ([`a6460db`](https://github.com/Byron/gitoxide/commit/a6460db80ba3c49ea37c712465c7cbdefa5c32b6))
+ - Release git-hash v0.9.3, git-features v0.20.0, git-config v0.2.0, safety bump 12 crates ([`f0cbb24`](https://github.com/Byron/gitoxide/commit/f0cbb24b2e3d8f028be0e773f9da530da2656257))
+ - Remove 'unused_mut' warning on windows ([`4733e6c`](https://github.com/Byron/gitoxide/commit/4733e6c6f5ea7d5afa4dd171bbba066cf5120ddc))
+ - Make fmt ([`7cf3545`](https://github.com/Byron/gitoxide/commit/7cf354509b545f7e7c99e159b5989ddfbe86273d))
+ - Commit to using 'unicode' feature of bstr as git-object wants it too ([`471fa62`](https://github.com/Byron/gitoxide/commit/471fa62b142ba744541d7472464d62826f5c6b93))
+ - Assure std::io::copy() doesn't hang when we cause an interrupt ([`234cd10`](https://github.com/Byron/gitoxide/commit/234cd10ca55482ce1a840ce3244308d249895bcc))
+ - Upgrade to prodash 19 ([`90c6c5a`](https://github.com/Byron/gitoxide/commit/90c6c5aec4015ff969d6e2514fa4d49873ee80f5))
+ - Thanks clippy ([`07a4094`](https://github.com/Byron/gitoxide/commit/07a4094965ac1b4eb223da8e5ca5cc4a86c5f596))
+ - Properly document optional features ([`572e57d`](https://github.com/Byron/gitoxide/commit/572e57d5796692764c5c9633969aad25a6f9221a))
+ - Merge branch 'svetli-n-path_value' ([`e8383ca`](https://github.com/Byron/gitoxide/commit/e8383caf6db211beb57d70019fe4ad13ce9066ee))
+ - Small refactoring and documentation. ([`fefb01b`](https://github.com/Byron/gitoxide/commit/fefb01b84f954700b19e010282c4b413de8e03d2))
+ - Upgrade document-features ([`c35e62e`](https://github.com/Byron/gitoxide/commit/c35e62e0da9ac1f7dcb863f5f9c69108c728d32e))
+ - Merge branch 'unify-path-encoding' ([`566ff8a`](https://github.com/Byron/gitoxide/commit/566ff8a3597b889899d41ca15e5b9af7e05f1a4b))
+ - Thanks clippy ([`a8e9497`](https://github.com/Byron/gitoxide/commit/a8e9497caebf1c0e9faac537717cd86378f1acf6))
+ - Release git-features v0.19.1, git-actor v0.8.0, git-config v0.1.10, git-object v0.17.0, git-diff v0.13.0, git-tempfile v1.0.4, git-chunk v0.3.0, git-traverse v0.12.0, git-pack v0.16.0, git-odb v0.26.0, git-packetline v0.12.3, git-url v0.3.5, git-transport v0.15.0, git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0 ([`d78aab7`](https://github.com/Byron/gitoxide/commit/d78aab7b9c4b431d437ac70a0ef96263acb64e46))
+ - Release git-hash v0.9.1, git-features v0.19.1, git-actor v0.8.0, git-config v0.1.10, git-object v0.17.0, git-diff v0.13.0, git-tempfile v1.0.4, git-chunk v0.3.0, git-traverse v0.12.0, git-pack v0.16.0, git-odb v0.26.0, git-packetline v0.12.3, git-url v0.3.5, git-transport v0.15.0, git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0, safety bump 4 crates ([`373cbc8`](https://github.com/Byron/gitoxide/commit/373cbc877f7ad60dac682e57c52a7b90f108ebe3))
+ - Prepare changelogs for release ([`674ec73`](https://github.com/Byron/gitoxide/commit/674ec73b0816baa2c63b4ef1b40b7a41849c5e95))
+ - Prepar changelogs for cargo-smart-release release ([`8900d69`](https://github.com/Byron/gitoxide/commit/8900d699226eb0995be70d66249827ce348261df))
+ - Upgrade to tui 0.17 and prodash 18 ([`eba101a`](https://github.com/Byron/gitoxide/commit/eba101a576ecb7bc0f63357d0dd81eb817b94be4))
+ - Release git-bitmap v0.0.1, git-hash v0.9.0, git-features v0.19.0, git-index v0.1.0, safety bump 9 crates ([`4624725`](https://github.com/Byron/gitoxide/commit/4624725f54a34dd6b35d3632fb3516965922f60a))
+ - Upgrade dependencies ([`968df47`](https://github.com/Byron/gitoxide/commit/968df4746729556dcf4f5039b1d1ed1a1da2705a))
+ - Refactor ([`e7fbd9f`](https://github.com/Byron/gitoxide/commit/e7fbd9f3700496ad7bb7e71226c4d25429f0ccd5))
+ - Merge branch 'sync-db-draft' ([`7d2e20c`](https://github.com/Byron/gitoxide/commit/7d2e20c6fedc2c7e71a307d8d072412fa847a4aa))
+ - Thanks clippy ([`7dd2313`](https://github.com/Byron/gitoxide/commit/7dd2313d980fe7c058319ae66d313b3097e3ae5f))
+ - Release git-features v0.18.0, git-actor v0.7.0, git-config v0.1.9, git-object v0.16.0, git-diff v0.12.0, git-traverse v0.11.0, git-pack v0.15.0, git-odb v0.25.0, git-packetline v0.12.2, git-transport v0.14.0, git-protocol v0.13.0, git-ref v0.10.0, git-repository v0.13.0, cargo-smart-release v0.7.0, safety bump 12 crates ([`acd3737`](https://github.com/Byron/gitoxide/commit/acd37371dcd92ebac3d1f039224d02f2b4e9fa0b))
+ - Adjust changelogs prior to release ([`ec38950`](https://github.com/Byron/gitoxide/commit/ec3895005d141abe79764eaff7c0f04153e38d73))
+ - Thanks clippy ([`db1bb99`](https://github.com/Byron/gitoxide/commit/db1bb99101a9248b464b0df9f526067b8f2a184e))
+ - Merge branch 'pack-consistency' ([`5982406`](https://github.com/Byron/gitoxide/commit/5982406b4e1b26fd383d9ec21a3cf652ec8ab25f))
+ - Release git-hash v0.8.0, git-features v0.17.0, git-actor v0.6.0, git-object v0.15.0, git-diff v0.11.0, git-traverse v0.10.0, git-pack v0.13.0, git-odb v0.23.0, git-packetline v0.12.0, git-transport v0.13.0, git-protocol v0.12.0, git-ref v0.9.0, git-repository v0.11.0, git-commitgraph v0.6.0, gitoxide-core v0.12.0, gitoxide v0.10.0, cargo-smart-release v0.5.0, safety bump 16 crates ([`0e02953`](https://github.com/Byron/gitoxide/commit/0e029537a7f6242d02ccf7e63d8d92f5246e6c5e))
+ - Release git-hash v0.7.0, git-features v0.16.5, git-actor v0.5.3, git-config v0.1.7, git-validate v0.5.3, git-object v0.14.1, git-diff v0.10.0, git-tempfile v1.0.3, git-lock v1.0.1, git-traverse v0.9.0, git-pack v0.12.0, git-odb v0.22.0, git-packetline v0.11.0, git-url v0.3.4, git-transport v0.12.0, git-protocol v0.11.0, git-ref v0.8.0, git-repository v0.10.0, cargo-smart-release v0.4.0 ([`59ffbd9`](https://github.com/Byron/gitoxide/commit/59ffbd9f15583c8248b7f48b3f55ec6faffe7cfe))
+ - Adjusting changelogs prior to release of git-hash v0.7.0, git-features v0.16.5, git-actor v0.5.3, git-validate v0.5.3, git-object v0.14.1, git-diff v0.10.0, git-tempfile v1.0.3, git-lock v1.0.1, git-traverse v0.9.0, git-pack v0.12.0, git-odb v0.22.0, git-packetline v0.11.0, git-url v0.3.4, git-transport v0.12.0, git-protocol v0.11.0, git-ref v0.8.0, git-repository v0.10.0, cargo-smart-release v0.4.0, safety bump 3 crates ([`a474395`](https://github.com/Byron/gitoxide/commit/a47439590e36b1cb8b516b6053fd5cbfc42efed7))
+ - Make fmt, but now it picked up some parts that usually don't get altered… ([`01f7b72`](https://github.com/Byron/gitoxide/commit/01f7b729337bd2c99498321c479a9a13b1858e3e))
+ - Release git-features v0.16.4 ([`fd189c7`](https://github.com/Byron/gitoxide/commit/fd189c7d973ad2a639d319f3761f37aa90712ef6))
+ - Merge branch 'repository-integration' ([`49f5453`](https://github.com/Byron/gitoxide/commit/49f5453629646ac24d752f53c532e5f67eb09374))
+ - Bump git-hash v0.6.0 ([`6efd90d`](https://github.com/Byron/gitoxide/commit/6efd90db54f7f7441b76159dba3be80c15657a3d))
+ - [features #190] be more explicit about why sha1-asm is disabled ([`507d710`](https://github.com/Byron/gitoxide/commit/507d710d837c3911a9329c1c132eee912a37e1a8))
+ - [various #190] rename 'local-offset' to 'local-time-support' ([`3a7d379`](https://github.com/Byron/gitoxide/commit/3a7d3793a235ac872437f3bfedb9dd8fde9b31b1))
+ - [actor #190] methods to get an actor signature at the current time ([`6d0bedd`](https://github.com/Byron/gitoxide/commit/6d0beddb20092a80b113a39c862d6b680d79deb6))
+ - [features #189] simple UTC-offset support for git-features ([`b58134b`](https://github.com/Byron/gitoxide/commit/b58134bbd132f9e685d1adf7859ec5219c16dd25))
+ - [features #???] WIP local time ([`1388ebf`](https://github.com/Byron/gitoxide/commit/1388ebf0925eb326ec3045d7f83bd5beda22a6fe))
+ - [#189] Upgrade to prodash 16… ([`8e98418`](https://github.com/Byron/gitoxide/commit/8e98418652926860f58906a6f21a3210e2f0183f))
+ - [pack #67] Optimize caches based on cache debugging ([`1271c01`](https://github.com/Byron/gitoxide/commit/1271c01d2635ab49474add61a9feb78b98bd6180))
+ - [pack #67] Add cache debugging capabilities to git-features ([`8776c98`](https://github.com/Byron/gitoxide/commit/8776c9834ac4622b3057f5db464a9817ed9acdb0))
+ - Merge branch 'main' into 162-repo-design-sketch ([`e63b634`](https://github.com/Byron/gitoxide/commit/e63b63412c02db469fbdb17da82cd1e9fda1ef0f))
+ - Thanks clippy ([`d689599`](https://github.com/Byron/gitoxide/commit/d689599d1b819c18a3be60075170dbe00462e216))
+ - [features] refactor ([`0958fc8`](https://github.com/Byron/gitoxide/commit/0958fc8dbaa72dda0c1e2d40a88d74b4e18bfe39))
+ - [features] refactor ([`d4605cd`](https://github.com/Byron/gitoxide/commit/d4605cde6d825c0bfaf4282c4cbd85d9f07dc43f))
+ - Release git-features v0.16.2 ([`42861ca`](https://github.com/Byron/gitoxide/commit/42861ca4f0cc9b741d033d4ffa50147b08513b58))
+ - Apply nightly rustfmt rules. ([`5e0edba`](https://github.com/Byron/gitoxide/commit/5e0edbadb39673d4de640f112fa306349fb11814))
+ - (cargo-release) version 0.16.1 ([`e10e55c`](https://github.com/Byron/gitoxide/commit/e10e55c1bf1b40965da9b8b6c87953e6eafda09a))
+ - (cargo-release) version 0.5.0 ([`ae02dab`](https://github.com/Byron/gitoxide/commit/ae02dabae961089a92a21e6a60a7006de4b56dad))
+ - (cargo-release) version 0.16.0 ([`1231dbd`](https://github.com/Byron/gitoxide/commit/1231dbd16dacefb39adec8e067c312d313a82e3c))
+ - Upgrade prodash/crosstermion ([`f109409`](https://github.com/Byron/gitoxide/commit/f1094099de028deabbee3587a70291a7e625e328))
+ - Clippy on tests and thanks clippy ([`a77a71c`](https://github.com/Byron/gitoxide/commit/a77a71cf02d328a2a964388928d6b2a235a0aa85))
+ - [pack] fix build ([`98dd557`](https://github.com/Byron/gitoxide/commit/98dd557b963acfe1c4e717451d222c187c46a5da))
+ - [pack] all tests running for now, but… ([`aec8439`](https://github.com/Byron/gitoxide/commit/aec8439683c639f7b6e344cb76bf1dd9fc769d17))
+ - Refactor sha-1 specification to avoid duplication ([`e23d19c`](https://github.com/Byron/gitoxide/commit/e23d19cd339f0ca5420c82e8125d2c9c7dfcb0da))
+ - Resolver = 2: works! ([`6dc8779`](https://github.com/Byron/gitoxide/commit/6dc877993135ce86649b239821e5b374251743d0))
+ - Try windows one more time: resolver = "2" ([`69d52b8`](https://github.com/Byron/gitoxide/commit/69d52b8ed7a733fe7f31826e576ba8b19619b148))
+ - Fix windows, leave todo, move on ([`2de9e78`](https://github.com/Byron/gitoxide/commit/2de9e78dba35de31456eb553ae703120de23cba6))
+ - See if turning off "asm" support entirely fixes windows ([`b804ef2`](https://github.com/Byron/gitoxide/commit/b804ef2ea6da1ebffaab4d09d0b91eae98ff70c9))
+ - Try to fix build, again ([`c616627`](https://github.com/Byron/gitoxide/commit/c616627cc9984e40798120a801387fc179d6640b))
+ - Don't use ASM on windows for Sha1 as it fails to build there. ([`ba1fb7a`](https://github.com/Byron/gitoxide/commit/ba1fb7ab5bc03f5a23ece32ff1e144544e1eaeae))
+ - [features] enable ASM for everyone… ([`7a1128f`](https://github.com/Byron/gitoxide/commit/7a1128f594c5395a22e5e2b23772bce1d4de7a37))
+ - [ref] reproducible loose ref iteration with built-in sorting ([`e138748`](https://github.com/Byron/gitoxide/commit/e13874807ccc3cbc2b4aacccf63ac5c3dd21c445))
+ - [features] fix docs in the absence of sha1 related features ([`6ca02ac`](https://github.com/Byron/gitoxide/commit/6ca02ace7552c1ffaead81929bc751d96afa713a))
+ - Remove unnecessary pub(crate) exports ([`3d2456e`](https://github.com/Byron/gitoxide/commit/3d2456e11709f0461b37c6df55ecc3861ca4cab5))
+ - [ref] first rough implementation of loose ref iteration ([`918af42`](https://github.com/Byron/gitoxide/commit/918af425298a1fdbb8e7dd6328daefe9eaa10cef))
+ - Refactor ([`2174513`](https://github.com/Byron/gitoxide/commit/21745135ced62411be535ebbc827b3638726318b))
+ - Fix docs ([`e68d460`](https://github.com/Byron/gitoxide/commit/e68d460716dc51c7f4757c11f3c8af6c3881e2cf))
+ - Remove mentions of interrupt handling feature toggles ([`833ac04`](https://github.com/Byron/gitoxide/commit/833ac0464b42bd3ecc76c6263b4b06e8ab4ff182))
+ - Fix everything up so that… ([`5930563`](https://github.com/Byron/gitoxide/commit/5930563601d6c2148cf39e109f69f8b7c7dfcb36))
+ - A first attempt to make intrerupt tools work, but… ([`8fb8d37`](https://github.com/Byron/gitoxide/commit/8fb8d374ecfeffa3ae1bd07bf9bc5014351730f5))
+ - First step towards moving git-features::interrupt… ([`8a741d0`](https://github.com/Byron/gitoxide/commit/8a741d0c5423ed7c35d9382307c760a6b9460ccd))
+ - Fix build ([`ea2bfac`](https://github.com/Byron/gitoxide/commit/ea2bfac65f742ca7617bc77a50376c29156c4ea5))
+ - Refactor ([`7f9be36`](https://github.com/Byron/gitoxide/commit/7f9be36ea909ee67555591287bcb140fdc54c801))
+ - And one less usage of the global interrupt handler… ([`5da57a3`](https://github.com/Byron/gitoxide/commit/5da57a3b0efef75ad82cb4d1cd496fc7fc0f1c23))
+ - Make most interrupts local to the method or function ([`4588993`](https://github.com/Byron/gitoxide/commit/458899306a3f3c8578f185d7ecbf1ade2a7142dd))
+ - Fix build ([`04d919f`](https://github.com/Byron/gitoxide/commit/04d919f9228d287912554275194487870500d18c))
+ - Refactor ([`e0b7f69`](https://github.com/Byron/gitoxide/commit/e0b7f695ee6bd1032544a29d91906f9b75e12d46))
+ - [features] sketch of iterator to auto-check for interruptions ([`61d3a15`](https://github.com/Byron/gitoxide/commit/61d3a15c66b4c1be1d98715b8a60705a3a314455))
+ - [tempfile] integrate with git-features to have a single top-level interrupt… ([`6e9400d`](https://github.com/Byron/gitoxide/commit/6e9400d9cb8e370d870c3aa635718b134c82268f))
+ - [features] protect interrupt handler from multi-initialization ([`592404c`](https://github.com/Byron/gitoxide/commit/592404c2b24dc9d24465ff5f73216213436a277a))
+ - [interrupt] remove any user mesasages as it can't be done in a handler. ([`8a10af7`](https://github.com/Byron/gitoxide/commit/8a10af77db654ebce940bb05f8eefd171036ef40))
+ - [tempfile] a first somewhat working version of signal-hooks for interrupt handling ([`07b3242`](https://github.com/Byron/gitoxide/commit/07b3242e446cb4520dbc54308632ab6221fc19c8))
+ - Update to latest prodash to get rid of ctrlc ([`c070d6f`](https://github.com/Byron/gitoxide/commit/c070d6f5273d7ef9049ddd02fd26332623dc0ae6))
+ - Refactor ([`2e86723`](https://github.com/Byron/gitoxide/commit/2e8672312a4b1e2638e3ffe82a97cc2f87b496cf))
+ - Bump crossbeam-utils from 0.8.4 to 0.8.5 ([`fce4d10`](https://github.com/Byron/gitoxide/commit/fce4d107c7abc778bbdfcd37349c3075e54fd756))
+ - (cargo-release) version 0.4.0 ([`866f86f`](https://github.com/Byron/gitoxide/commit/866f86f59e66652968dcafc1a57912f9849cb21d))
+ - [git-pack] fix docs ([`efd20d4`](https://github.com/Byron/gitoxide/commit/efd20d4e1afbfbe573d620dea4761c06f948a296))
+ - [git-features] fix compilation ([`38c7961`](https://github.com/Byron/gitoxide/commit/38c796142dc5823e1cb14906d9cd4040a8c3be3a))
+ - [git-pack] move hash-writer to git-features as it's quite general purpose ([`80e5640`](https://github.com/Byron/gitoxide/commit/80e5640169363910b4189fda58bb495c6677eaaa))
+ - [git-features] Remove feature that would break licensing agreements ([`cd6ce67`](https://github.com/Byron/gitoxide/commit/cd6ce673308e7e5b1e86fb682ee3ace2ca9ae18c))
+ - [git-features] fix typo ([`c6f342f`](https://github.com/Byron/gitoxide/commit/c6f342f3d29a969a08d037f01eb24555bc03e85e))
+ - [git-features] Finally zlib with feature toggles is working… ([`057016e`](https://github.com/Byron/gitoxide/commit/057016e2df3138992c4857f9b65bf19dc2c9a097))
+ - [git-features] And now zlib finally works! ([`6d887d5`](https://github.com/Byron/gitoxide/commit/6d887d589a57e159986f049c8a9e19c52ce7b85b))
+ - [git-features] simplify even more ([`ca54d97`](https://github.com/Byron/gitoxide/commit/ca54d97d579dd4f16025a2325d5e39431f6e8a36))
+ - [git-features] refactor to help understand a zlib-related logic bug ([`ae826e8`](https://github.com/Byron/gitoxide/commit/ae826e8c3240efd14939beedd33a06695a6c112b))
+ - [git-features] a first step towards supporting a pure rust zlib backend ([`040cab7`](https://github.com/Byron/gitoxide/commit/040cab7f27de83b283957189244d523d71ca1457))
+ - [git-features] Add zlib module to allow changing implementation on the fly ([`4bdf783`](https://github.com/Byron/gitoxide/commit/4bdf7833d99d3c2884b9747614f9c14a06c1e945))
+ - (cargo-release) version 0.15.0 ([`d69d9fb`](https://github.com/Byron/gitoxide/commit/d69d9fb0931f8257cef96ef14a89da9340ad9738))
+ - Put prodash behind a feature toggle, too ([`966058d`](https://github.com/Byron/gitoxide/commit/966058d611c548e90c050462de52e36f1925e775))
+ - Put 'walkdir' behind a feature flag/make it optional. ([`1a3cc5b`](https://github.com/Byron/gitoxide/commit/1a3cc5bea1868ed3ae015403fbe0cdec788be749))
+ - Put 'sha1' behind a feature toggle ([`4f326bc`](https://github.com/Byron/gitoxide/commit/4f326bc261c4e7f0d5510df74ad4215da3580696))
+ - Use crc32fast instead of `crc` ([`11955f9`](https://github.com/Byron/gitoxide/commit/11955f95e200ef75e752a833952d288fbd0fc389))
+ - Put crc functionality behind a feature toggle ([`458fa6e`](https://github.com/Byron/gitoxide/commit/458fa6ec726ec7901c1f6d970cbb1c1ea975dded))
+ - (cargo-release) version 0.14.0 ([`a760f8c`](https://github.com/Byron/gitoxide/commit/a760f8c013e13ba82daa1acf1a4a57e0818a008d))
+ - Upgrade to prodash 13/tui 0.15 ([`1c99f51`](https://github.com/Byron/gitoxide/commit/1c99f51b35b4ba85792a3b32dbb7e48052facc5e))
+ - (cargo-release) version 0.3.0 ([`e9665c7`](https://github.com/Byron/gitoxide/commit/e9665c784ae7e5cdaf662151395ee2355e9b57b6))
+ - Allow calling 'finalize()' on the entries iterator ([`3c617bc`](https://github.com/Byron/gitoxide/commit/3c617bc2ae59adbb12c254308269e745149d462b))
+ - Git-odb without cargo warnings due to using the same test twice ([`8945f95`](https://github.com/Byron/gitoxide/commit/8945f95364b489e7a639d74dd0f28b17e82e70f3))
+ - Fix compile warning for git-features ([`d457faa`](https://github.com/Byron/gitoxide/commit/d457faac6bb56a229b74147c8a4cf2484026bb1a))
+ - Fix doc links ([`870af2a`](https://github.com/Byron/gitoxide/commit/870af2a6949bcb1f7f45bc0ff98d9e9a07014b22))
+ - Run git-odb tests in parallel, too; improved threaded error handling ([`40802fd`](https://github.com/Byron/gitoxide/commit/40802fd8bbb15b8a61249522d67f3a5b28da64b3))
+ - Refactor ([`82c2f42`](https://github.com/Byron/gitoxide/commit/82c2f428e22c3cda79913c9ca2f092c377d692aa))
+ - Refactor ([`7a6b514`](https://github.com/Byron/gitoxide/commit/7a6b514a5b9b93bf574cd3a114f27ad5967e89ac))
+ - Refactor ([`5ef1f22`](https://github.com/Byron/gitoxide/commit/5ef1f22c1e12ff8d607663d4dfbbbfe426a29e0f))
+ - Fix docs #(67) ([`01db10a`](https://github.com/Byron/gitoxide/commit/01db10a27431ad89a68ed3e4eabae810748a6f29))
+ - Refactor ([`3e908bd`](https://github.com/Byron/gitoxide/commit/3e908bd4b4077c4a5d113cefc113f9d71f249133))
+ - Refactor ([`409d763`](https://github.com/Byron/gitoxide/commit/409d763d2fca974a647487c72d15f568a9b62ccb))
+ - Refactor ([`896ab94`](https://github.com/Byron/gitoxide/commit/896ab940bcd475d026e4009b3aa2fa6a025c14bc))
+ - Remove unused dependency ([`26beb2a`](https://github.com/Byron/gitoxide/commit/26beb2a5ad87e173fd3d13d17b0e9676a650cac9))
+ - Don't finish the computation on drop of SteppedReduce ([`6453633`](https://github.com/Byron/gitoxide/commit/6453633f1420327aee07dca2ad27abd8f96108c0))
+ - Thanks clippy ([`c320761`](https://github.com/Byron/gitoxide/commit/c320761821b08946a2b37e219400ded853a86408))
+ - Remove unsafe interface for stepped computation #(67) ([`c856613`](https://github.com/Byron/gitoxide/commit/c856613a35aea7dea1d093bfcfe1ddbde93fdf26))
+ - A first working version of a static parallel iterator #(67) ([`d7d5c68`](https://github.com/Byron/gitoxide/commit/d7d5c6855a038a8b01571a6a16a61fe0d8036d30))
+ - A way iteration won't work with 'static #(67) ([`6fda1f2`](https://github.com/Byron/gitoxide/commit/6fda1f20a57b9dcc1a5818d8d0b656218b383230))
+ - Sketch of machinery for producing pack entries #(67) ([`ac8e7fb`](https://github.com/Byron/gitoxide/commit/ac8e7fb6c8ae4ac42f56482d9d7744aa66132702))
+ - Less restrictive requirements: Clone instead of Copy #(67) ([`410e7d6`](https://github.com/Byron/gitoxide/commit/410e7d64049b5a749113126f5412a61ae4b79887))
+ - Improve Safety docs #(67) ([`15e4748`](https://github.com/Byron/gitoxide/commit/15e47480054d9a517c28f47db3b5fa87968a307e))
+ - A test to assure referenced input and references in 'consume' work #(67) ([`4526d82`](https://github.com/Byron/gitoxide/commit/4526d82fab4d6e8f2ab05497aa5893d5a8f8b253))
+ - Make iterator creation unsafe and document why #(67) ([`593d5df`](https://github.com/Byron/gitoxide/commit/593d5df478e67e28f9b3d48b201ff6830208726f))
+ - First seemingly working version of an iterator which allows controlling threaded work #(67) ([`4a7ef7d`](https://github.com/Byron/gitoxide/commit/4a7ef7d6398c2ff5dd6aac41f8224cd2d61ee189))
+ - Make the parallel SteppedReduce compile #(67) ([`017fdf4`](https://github.com/Byron/gitoxide/commit/017fdf48972a6a09e5155bd76bd437d8e195dae3))
+ - More docs to differentiate SteppedReduce from in_parallel() #(67) ([`153c083`](https://github.com/Byron/gitoxide/commit/153c0837bbf1df3b5cb386e08265f9b06eaee2a9))
+ - Serial version of SteppedReduce seems to be working #(67) ([`779542e`](https://github.com/Byron/gitoxide/commit/779542e4f4c951e9b16d2310146020da9ce36859))
+ - Only store thread state #(67) ([`0bf8a9b`](https://github.com/Byron/gitoxide/commit/0bf8a9b3c4a086732ee04f81c6a214296d49eab9))
+ - Sketch instantiation of iterator adapter #(67) ([`a3083ad`](https://github.com/Byron/gitoxide/commit/a3083ad3aad7984afc6b6d343ca7453f79897062))
+ - A reducer test in preparation for allow it to be used as iterator #(67) ([`1c2adf4`](https://github.com/Byron/gitoxide/commit/1c2adf4a546273489bf8224eb7982dbdf3fb6aca))
+ - (cargo-release) version 0.13.0 ([`ac2eddb`](https://github.com/Byron/gitoxide/commit/ac2eddb06eb3d8a9a3dcdcd796eb54a7e45ab935))
+ - Allow parallel reducers to produce something during 'feed()' #(67) ([`6c04fcd`](https://github.com/Byron/gitoxide/commit/6c04fcd643083d9db633edd3bb838b4f5de8f0db))
+ - (cargo-release) version 0.12.0 ([`3b71e7e`](https://github.com/Byron/gitoxide/commit/3b71e7e8416e550b47e5aed2259c1181497ac9e8))
+ - (cargo-release) version 0.2.0 ([`4ec09f4`](https://github.com/Byron/gitoxide/commit/4ec09f4d2239ea1d44f7145027e64191bf2c158c))
+ - Refactor ([`dee8c66`](https://github.com/Byron/gitoxide/commit/dee8c66e300dc2a2b6e1a6d6c3674a7ce6aac687))
+ - (cargo-release) version 0.11.0 ([`1aa1f5e`](https://github.com/Byron/gitoxide/commit/1aa1f5e84a07427d5d7f3231735fe9c1923f506f))
+ - (cargo-release) version 0.10.1 ([`0dcdfd7`](https://github.com/Byron/gitoxide/commit/0dcdfd754649240f43fe0f4b6e1245e8c7b89635))
+ - Remove usage of gitfeatures::fs in organize subcommand ([`b567d37`](https://github.com/Byron/gitoxide/commit/b567d3709a74e9fdafef54b0fe58ca82721cd773))
+ - Assure basic 'organize' operation is working as expected ([`deb6073`](https://github.com/Byron/gitoxide/commit/deb6073671ae95de674aaef7ca01e03f95b41ca8))
+ - A first stab at finding git repositories ([`e4dc964`](https://github.com/Byron/gitoxide/commit/e4dc96403894f1fe509335905679347ecdf535c7))
+ - Upgrade 'jwalk' ([`cba048f`](https://github.com/Byron/gitoxide/commit/cba048f094858388f4242e37a2409fe0822f8c07))
+ - Upgrade 'bytes' ([`3934392`](https://github.com/Byron/gitoxide/commit/39343922b4a1129394aa788a9591920aee077569))
+ - Upgrade prodash and friends ([`50755bc`](https://github.com/Byron/gitoxide/commit/50755bc83f73072dc629301bf69c5c065d5c2aa4))
+ - Add missing '.' at end of doc comments ([`7136854`](https://github.com/Byron/gitoxide/commit/71368544f97369a4d371d43513607c4805bd0fd0))
+ - Use git-hash in git-features ([`5b307e0`](https://github.com/Byron/gitoxide/commit/5b307e076f6f5975592c8b177c122c91c1d809c6))
+ - (cargo-release) version 0.9.0 ([`a89fdb9`](https://github.com/Byron/gitoxide/commit/a89fdb98f64bb0ca070fa79a1f58f1232bb14090))
+ - (cargo-release) version 0.5.0 ([`fc7d600`](https://github.com/Byron/gitoxide/commit/fc7d600ac2c438c8b6b91f67cb69b0ac5ec37675))
+ - More docs for owned git-object ([`b79101d`](https://github.com/Byron/gitoxide/commit/b79101d714f59a42a30eb47776486a212ec0f738))
+ - Fix io::pipe tests ([`9604154`](https://github.com/Byron/gitoxide/commit/9604154e687813a11f0eee469e408561a6a74a4e))
+ - Uograde everything else ([`0cd79d0`](https://github.com/Byron/gitoxide/commit/0cd79d00bce3f042b5cc849cf48739e29f95fcb0))
+ - Upgrade prodash and tui ([`b5eadca`](https://github.com/Byron/gitoxide/commit/b5eadca343bbaa1af86722b5f1bcd33f4e3939a6))
+ - Add remaining docs to git-features using the missing_docs directive ([`f8aafd6`](https://github.com/Byron/gitoxide/commit/f8aafd6c78687899a2ca3a3e6147d93fc45b8cb9))
+ - (cargo-release) version 0.8.0 ([`47c00c2`](https://github.com/Byron/gitoxide/commit/47c00c2228cf25c79e1fa3eb4229c7ab24de91e5))
+ - Finish git-features documentation ([`934a26c`](https://github.com/Byron/gitoxide/commit/934a26c5e254baf2be9178096b6dead0e4c1ed1d))
+ - Refactor ([`b3a8bb5`](https://github.com/Byron/gitoxide/commit/b3a8bb5f7f0c6e80259922546928c2739c24f7b5))
+ - Refactor ([`f9e8d29`](https://github.com/Byron/gitoxide/commit/f9e8d2932c02c22bf57acd39fb0a9e6d521070bd))
+ - Docs for the git-features::pipe module ([`67a950a`](https://github.com/Byron/gitoxide/commit/67a950a2e0fd56b29565668ed0a0f399d5aa989d))
+ - Document git-features::parallel ([`b899227`](https://github.com/Byron/gitoxide/commit/b8992275cd4310b05494be41c059e9b6049d06b1))
+ - Dependency update ([`fb077f9`](https://github.com/Byron/gitoxide/commit/fb077f9fecb89ed8a60d57b45726401883e838bf))
+ - Finish git_features::interrupt docs ([`471a1bf`](https://github.com/Byron/gitoxide/commit/471a1bf24efee70f21b15839cdc9f8ebe319f917))
+ - Dependency update ([`b3b4aba`](https://github.com/Byron/gitoxide/commit/b3b4aba5e05596befecd17e225067be9315b74fd))
+ - Docs for git-features::hash ([`a3fdecc`](https://github.com/Byron/gitoxide/commit/a3fdecc9a3587b20c01e3b3a2d51190138131c3d))
+ - First sketch of filesystem docs for git-features ([`1a8141c`](https://github.com/Byron/gitoxide/commit/1a8141c2c4a8bcc79d68049a35bd8aba5ab822a3))
+ - (cargo-release) version 0.7.0 ([`7fa7bae`](https://github.com/Byron/gitoxide/commit/7fa7baeb3e7d008a25e4d714eff908e2516c828b))
+ - Merge branch 'commit-graph' into main ([`9cb09b2`](https://github.com/Byron/gitoxide/commit/9cb09b248796f0ff5c9d3f3e857de4731324cfd5))
+ - Specify the hash to create with 'hash::bytes_of_file' ([`c000294`](https://github.com/Byron/gitoxide/commit/c000294423ae0759b978399db3b69ac07c20578d))
+ - Move 'git_odb::hash::bytes_of_file' into git_features::hash ([`c5f6b45`](https://github.com/Byron/gitoxide/commit/c5f6b4587ee4042a080c0505613b0c72fdfe5273))
+ - Remove dash in all repository links ([`98c1360`](https://github.com/Byron/gitoxide/commit/98c1360ba4d2fb3443602b7da8775906224feb1d))
+ - Merge branch 'main' into commit-graph ([`ca5b801`](https://github.com/Byron/gitoxide/commit/ca5b80174b73cc9ac162b3f33b5d3721ef936cb1))
+ - Use parallel walkdir (via jwalk) when parallel feature is enabled ([`f444c85`](https://github.com/Byron/gitoxide/commit/f444c859f5b215ea70a46d5493a2babbf7a98235))
+ - Merge from main. ([`b59bd5e`](https://github.com/Byron/gitoxide/commit/b59bd5e0b0895c7d1d585816cec8be4dea78c278))
+ - Refactor ([`e4bcfe6`](https://github.com/Byron/gitoxide/commit/e4bcfe6406b14feffa63598c7cdcc8ecc73222bd))
+ - (cargo-release) version 0.6.0 ([`9ef184e`](https://github.com/Byron/gitoxide/commit/9ef184e35712f938fb4f9f6da7390a8777a9284e))
+ - Switch to prodash 10 and safe a lot of trait bounds in the process ([`e2fb1d9`](https://github.com/Byron/gitoxide/commit/e2fb1d944b4d803a11c91f868b831d406fb5e35f))
+ - (cargo-release) version 0.5.0 ([`82b7313`](https://github.com/Byron/gitoxide/commit/82b73131b79ec3c42a712dad1c0766a72209d737))
+ - [clone] This actually works: first MVP of retrieving packs via clone ([`c06d819`](https://github.com/Byron/gitoxide/commit/c06d8194173f9ec468ddd0faf72dd6d8dbf7d35d))
+ - [clone] test (and fix) for piped line reading ([`afe2996`](https://github.com/Byron/gitoxide/commit/afe2996689b5bea915ac5f142d320056faf49899))
+ - [clone] Send headers with BufReaders ([`6a95aaa`](https://github.com/Byron/gitoxide/commit/6a95aaab582941c6d1697dde6982c0aa8896c73d))
+ - [clone] pipe allows to send errors as well ([`69286ec`](https://github.com/Byron/gitoxide/commit/69286ecb3680b5071693ef0d9fb2e9345b2722d4))
+ - [clone] BufRead for Reader… ([`bf1d40f`](https://github.com/Byron/gitoxide/commit/bf1d40f2d44a9b04ffe2134ddcd3779985cdafc4))
+ - [clone] a piped iterator ([`5148c85`](https://github.com/Byron/gitoxide/commit/5148c85efc70c0ec06be3ebce267ce727c8ee4e1))
+ - [clone] pipe probably shouldn't abort on empty writes ([`9cfa9b7`](https://github.com/Byron/gitoxide/commit/9cfa9b79841187167f0f96abfd1c17a37b4c365d))
+ - Thanks clippy ([`c4f570f`](https://github.com/Byron/gitoxide/commit/c4f570fcae7e21745a37a4265b05d21e6149157b))
+ - [clone] more pipe tests ([`1652a74`](https://github.com/Byron/gitoxide/commit/1652a74761631cadfc6feab366adc0808d83063d))
+ - [clone] first working pipe implementation ([`490a9b9`](https://github.com/Byron/gitoxide/commit/490a9b96915a760e339e576d9f49737b43a8739f))
+ - [clone] frame for implementing 'pipe' support ([`c555681`](https://github.com/Byron/gitoxide/commit/c55568127ff943cc6749dba5054d7b3e93c049eb))
+ - Fix git-features hash tests ([`35e8809`](https://github.com/Byron/gitoxide/commit/35e8809f6bc7d19ed9e0bac8e3af85f433978901))
+ - Bump git-features to 0.4 to allow publishes after breaking changes ([`9d6b879`](https://github.com/Byron/gitoxide/commit/9d6b8790e2edd7fa01b3239adff86a7cd2393f10))
+ - [protocol] properly implement remote progress reporting ([`a81954a`](https://github.com/Byron/gitoxide/commit/a81954a6a37afacd51add6661a656b8fb663ca54))
+ - Allow dual-licensing with Apache 2.0 ([`ea353eb`](https://github.com/Byron/gitoxide/commit/ea353eb02fd4f75508600cc5676107bc7e627f1e))
+ - Add 'disable-interrupts' feature flag ([`ccd9c3e`](https://github.com/Byron/gitoxide/commit/ccd9c3e2d37aa6898dc17f47a82c187baa810b03))
+ - Refactor ([`b4a6e16`](https://github.com/Byron/gitoxide/commit/b4a6e16364822c0dccb56f98dbfb0ca4c8007069))
+ - Bump minor version to 0.3 ([`4351e28`](https://github.com/Byron/gitoxide/commit/4351e2871c9dcf342b8471fffa74cae338a53269))
+ - Thanks clippy ([`6725104`](https://github.com/Byron/gitoxide/commit/6725104d2841e6518db641d06e3e107cf4f40f96))
+ - First step towards parallelizing file hashes and traversal! ([`9573836`](https://github.com/Byron/gitoxide/commit/95738369e0d3accf7f6239c8cd966a7f5c36825a))
+ - Better usability for units ([`b226253`](https://github.com/Byron/gitoxide/commit/b226253636d8146a084a7bcd7c0c320e37f9d2fb))
+ - Update dependencie ([`ade06b4`](https://github.com/Byron/gitoxide/commit/ade06b46bb3c16ac1e26dbbb4a7045f0c09f2d8e))
+ - Make obvious that interrupt request was received ([`34b2373`](https://github.com/Byron/gitoxide/commit/34b23737f560fe52d4f98fb886eba754652f9a5e))
+ - Remove once_cell dependency as it is really not required anymore ([`5ac9538`](https://github.com/Byron/gitoxide/commit/5ac95385cc8d1c50c16da6e5fb0c66ac138f9966))
+ - Make interrupt handler work reliably ([`e71da0f`](https://github.com/Byron/gitoxide/commit/e71da0fce6d6eab68f7b81b13cdc78ce8e9b7ee3))
+ - Conditionally use an eager iterator… ([`e9b5511`](https://github.com/Byron/gitoxide/commit/e9b5511568f4e64968596994855783f19672d678))
+ - Refactor ([`d14f0f6`](https://github.com/Byron/gitoxide/commit/d14f0f6c3b5f303df75b33aadbf16653075d2272))
+ - Allow eager iterator to behave properly when used with index writing ([`66ebc5f`](https://github.com/Byron/gitoxide/commit/66ebc5f1ad5f262eb464dc7ca0892ec952d34382))
+ - First successful test of moving the streaming iterator into its own thread ([`c9fcb68`](https://github.com/Byron/gitoxide/commit/c9fcb68c644c96a15cb9956a754bec7b65bb5fbd))
+ - Now it's order preserving ([`4c8711e`](https://github.com/Byron/gitoxide/commit/4c8711e51efd88e0f159ad02de2692c4cb72ce27))
+ - First sketch of order-destroying eager iterator ([`20fca45`](https://github.com/Byron/gitoxide/commit/20fca4515f6e9ea320d0bf21c15cd6d2c3cff742))
+ - Print read throughput automatically ([`0a71b48`](https://github.com/Byron/gitoxide/commit/0a71b482310a129aa8757475290b3b24a200b702))
+ - Make sure interrupt logic works even without an interrupt handler… ([`66b1644`](https://github.com/Byron/gitoxide/commit/66b164472f5893f9e634ac1f9147a41dc742296d))
+ - Add percentage and throughput to tasks that matter ([`763d7ca`](https://github.com/Byron/gitoxide/commit/763d7caa4c70111b7cb3ef5733d2c3c697758c28))
+ - Upgrade to latest iteration of prodash ([`3a4faec`](https://github.com/Byron/gitoxide/commit/3a4faecab56e37670c553e6563f11a46d740c333))
+ - First part of migration to prodash 8.0, but… ([`6901a09`](https://github.com/Byron/gitoxide/commit/6901a098641820c8d974ce56a24d6cdca779730d))
+ - Thanks clippy ([`ed5882d`](https://github.com/Byron/gitoxide/commit/ed5882d75e0a9fceb0628e84302eb49a66277fa6))
+ - Write about user interfaces and the use/non-use of async ([`91ba045`](https://github.com/Byron/gitoxide/commit/91ba0457745f860b7a68cb38b13e69754747e8d9))
+ - Interrupt support for pretty plumbing ([`bca7ce2`](https://github.com/Byron/gitoxide/commit/bca7ce2e668a4be2600d2d04d00f46b21c82eee2))
+ - Support for interruptible operations ([`a025593`](https://github.com/Byron/gitoxide/commit/a02559378f9165df97a217f24834a851be719b08))
+ - Refactor ([`413968d`](https://github.com/Byron/gitoxide/commit/413968dfee5e5a66ed9e63823f6bda5a5a22753e))
+ - Receive progress information when reading packs in bundle ([`759091d`](https://github.com/Byron/gitoxide/commit/759091d3c6696b427d7b5aab1b6da05a0d268c04))
+ - Initial batch of progress usage for index creation… ([`b10e5c6`](https://github.com/Byron/gitoxide/commit/b10e5c664be9bd1bdb2b72b858ebaf35c1ed4cb4))
+ - First stab at streaming pack header encoding ([`3c6e78b`](https://github.com/Byron/gitoxide/commit/3c6e78bec9cbd4df842919cc8dc3c575414ed002))
+ - We can now restore (possibly half-written) packs ([`b1daa46`](https://github.com/Byron/gitoxide/commit/b1daa465c40ea8c7c9de69a18e467d69459d911e))
+ - See how big a Sha1 hasher really is ([`26b271d`](https://github.com/Byron/gitoxide/commit/26b271d44863fb184b0a947c3a9da2b3252f9a78))
+ - First sketch of new verify expressed in terms of traversal ([`4cb570f`](https://github.com/Byron/gitoxide/commit/4cb570f96ddd7ee2faa62e54927afd78ba7822af))
+ - (cargo-release) version 0.2.0 ([`0bb8314`](https://github.com/Byron/gitoxide/commit/0bb831480d8657e1bb29ee7009aeac673471403e))
+ - Incorporate dynamic chunking into 'less-time' algorithm ([`295aa2f`](https://github.com/Byron/gitoxide/commit/295aa2f01dc596a8880cd2f68a8d83bc6913ce48))
+ - Integrate new chunk size code into lookup code ([`a8422cf`](https://github.com/Byron/gitoxide/commit/a8422cf0b0c9ff4d3275cc17a68a74811b5bd01f))
+ - First round of number tuning done ([`a647b2d`](https://github.com/Byron/gitoxide/commit/a647b2da2905c4079e646ea44cbec778f3f7c71f))
+ - Somehow handle chunk size in absence of known chunk amount ([`acfccad`](https://github.com/Byron/gitoxide/commit/acfccadef40ebcc67f8dea4e58c02392b7e2e7de))
+ - Chunk computation seems alright, what about realistic values ([`973e6bb`](https://github.com/Byron/gitoxide/commit/973e6bb3d67d89eec2faf2467a129d992b90ed72))
+ - Getting there… ([`a1b5d56`](https://github.com/Byron/gitoxide/commit/a1b5d565f305f0f2666fd59272d9bf9c62ae2962))
+ - First step towards computing better chunk sizes and thread limits ([`1cdde7d`](https://github.com/Byron/gitoxide/commit/1cdde7d339a6ed3650c54f9b48154089d7da9919))
+ - Add 'inc()' convenience methods to progress ([`2e46c9b`](https://github.com/Byron/gitoxide/commit/2e46c9b72a2a5b90bcdac249de07ffbc124cfb04))
+ - (more) graceful shutdown of failing parallel tasks ([`163f50f`](https://github.com/Byron/gitoxide/commit/163f50fab81b425e6e306ec54fb1eb60a7c02cf8))
+ - Respect thread limit in 'in_parallel' ([`babfd84`](https://github.com/Byron/gitoxide/commit/babfd84cba77ef7a0f541ba921b31ebd3f3c50e3))
+ - Make crates publishable ([`5688a34`](https://github.com/Byron/gitoxide/commit/5688a3427ff3673e1422d43106f4d685fa837aed))
+ - Flume isn't actually needed for that… ([`c750022`](https://github.com/Byron/gitoxide/commit/c750022394928aa37a8400611f6fdf4ee77c0f69))
+ - Don't just ignore send errors - we should panic for now ([`f128117`](https://github.com/Byron/gitoxide/commit/f128117138b24de780a00bb96e7c1c9f987e8aa0))
+ - Proper implementation of line renderer into 'lean' CLI ([`e98e7c2`](https://github.com/Byron/gitoxide/commit/e98e7c280d73e9d9ebd13202afb93a56cb2f7c9c))
+ - Upgrade to prodash version 7 ([`af02b46`](https://github.com/Byron/gitoxide/commit/af02b46cc1eff5ba1da7da20d3f524a79fad686f))
+ - Update prodash to verion 6.0 ([`a4731a3`](https://github.com/Byron/gitoxide/commit/a4731a3aca159f8916b29d9ce5a71856089c5a6b))
+ - Add metadata to allow docs.rs build all featueres ([`10f9386`](https://github.com/Byron/gitoxide/commit/10f9386a12decc1f13999aee72be484c8f6d48ce))
+ - Switch to prodash 5.0 for windows support ([`88542e1`](https://github.com/Byron/gitoxide/commit/88542e117dd1c2e7606fcbe88b30c51b4c115989))
+ - Allow to limit the logging depth for less cluttered output ([`fce7035`](https://github.com/Byron/gitoxide/commit/fce703531d7006f7d961d6ffa66f51f6c9bc0efc))
+ - Finally speed up logging progress properly - needs input throttling ([`1a550c6`](https://github.com/Byron/gitoxide/commit/1a550c6458b10fad2e42b641899216c5517c6e26))
+ - Avoid calling system time too often in logs, it reduced performance ([`b17bd76`](https://github.com/Byron/gitoxide/commit/b17bd76d35822b3af174c74af3d6fac887889fe2))
+ - Revert "ABORT: try-join with static typing works, but…" ([`b8b979b`](https://github.com/Byron/gitoxide/commit/b8b979b99b5f3848e0a6884c58594ba2b481a147))
+ - Try-join with static typing works, but… ([`ab6f98b`](https://github.com/Byron/gitoxide/commit/ab6f98b905f13ed2a7c0c483f34fab63141fbc5b))
+ - Remove dependency to git-object from git-features - it better remains free ([`67c3a6a`](https://github.com/Byron/gitoxide/commit/67c3a6ab4cc32358a1406c2f863e26a4c2929867))
+ - \#[forbid(unsafe)] for all crates ([`afda803`](https://github.com/Byron/gitoxide/commit/afda8039259b7a30cfed5dbcdd9caf4773b4c234))
+ - Allow for more screen space when formatting ([`6794300`](https://github.com/Byron/gitoxide/commit/67943002e7f4215b5383bd0538786ce2857f011e))
+ - Refactor ([`7add82c`](https://github.com/Byron/gitoxide/commit/7add82c39169e3c2fff76c48cdd318fe6040d7bc))
+ - Automatically close the TUI when there is no progress anymore. ([`c416152`](https://github.com/Byron/gitoxide/commit/c416152b04051958de7bd161a8a2ee42ca163275))
+ - Pretty progress in a generalized form ([`caa883b`](https://github.com/Byron/gitoxide/commit/caa883b96827deb63b5c8787ed820d22f2c85249))
+ - Express DoOrDiscard in terms of Either (progress) ([`cb29a45`](https://github.com/Byron/gitoxide/commit/cb29a45f4e73bfaa25cbf623b1cda2435673028b))
+ - Provide 'either' type with implementation for Progress ([`237bb5e`](https://github.com/Byron/gitoxide/commit/237bb5ee1c2b677f5bfd9ca7fdea9d9d2db865b3))
+ - Better trait bounds of `in_parallel_if`… ([`6264f2f`](https://github.com/Byron/gitoxide/commit/6264f2f99929ffaa4d50cdcae7bc296e1b4762f4))
+ - First implementation of logging per thread ([`477dd90`](https://github.com/Byron/gitoxide/commit/477dd90ce5e102875b19489bf8ae9877522ef9c8))
+ - Support for providing progress to threads ([`2815858`](https://github.com/Byron/gitoxide/commit/2815858adf7ac0f7b4cbc88cf05df0ea6aef4116))
+ - First very basic progress implementation ([`b820717`](https://github.com/Byron/gitoxide/commit/b8207177daee8a9ffa23c7c052cf9ca651b15804))
+ - Pass progress everywhere, for now just to discard it ([`da3ae1c`](https://github.com/Byron/gitoxide/commit/da3ae1c82cd726b8fae9b8d26069719930e9ba99))
+ - Implement `Progress` trait for prodash::tree::Item ([`0eeb6d7`](https://github.com/Byron/gitoxide/commit/0eeb6d770d58621427bc88107a20860b89b86a24))
+ - Implement progress trait for logs with throttling ([`287eca9`](https://github.com/Byron/gitoxide/commit/287eca91b244ccbc703cb275b1ae032bfeb02532))
+ - Add 'fast-sha1' to git-features ([`b22541f`](https://github.com/Byron/gitoxide/commit/b22541f0c39af470877119b136e4eb1b82dff2db))
+ - A new crate to represent features that can toggle from the top-level ([`23c420c`](https://github.com/Byron/gitoxide/commit/23c420cc95219dc7c04d3905aaa03281cb51724e))
+</details>
+
+## 0.26.3 (2023-02-14)
+
+### New Features
+
+ - <csr-id-426057247a80821b3da22b4ae5d67bda89ce0631/> re-export `prodash` in `progress` module.
+ That way one can access all types even if they are not re-exported.
+
+## 0.26.2 (2023-02-09)
+
+### Documentation
+
+ - <csr-id-39ed9eda62b7718d5109135e5ad406fb1fe2978c/> fix typos
+
+### New Features
+
+ - <csr-id-c4a7634b0b29c74625e183953e59c65987e9d66c/> export `prodash::progress::Id` in the `progress` module for convenience.
+
+## 0.26.1 (2023-01-10)
+
+A maintenance release without user-facing changes.
+
+## 0.26.0 (2022-12-30)
+
+<csr-id-5bf0034fb3918e57562b7089ceba83d63a1854bf/>
+
+### Chore (BREAKING)
+
+ - <csr-id-5bf0034fb3918e57562b7089ceba83d63a1854bf/> upgrade to prodash v23
+
+## 0.25.1 (2022-12-26)
+
+### New Features
+
+ - <csr-id-25ad372bf500b851105f53b10369b5a689ba167e/> zlib::inflate::Error can now represent zlib status codes that represent failure.
+
+## 0.25.0 (2022-12-19)
+
+### New Features (BREAKING)
+
+ - <csr-id-0f27c67c92fc0bc23a6712b5c4c730ad6a0156bf/> add support for explicit non-parallel iteration.
+ That way we can allow the implementation to choose whether they
+ need greatest speed at some cost or not.
+
+ This also allows us to create a new thread-pool on each iteration
+ as those who expect high cost or many files will likely chose to do
+ that instead of single-threaded iteration, which nicely contains the
+ threads needed and avoids keeping them alive as part of some global pool.
+
+## 0.24.1 (2022-11-27)
+
+### New Features
+
+ - <csr-id-6d530a1dc77f0f4ac00622a2fd47c7bdb731a77a/> name spawned threads
+ That way it's a bit more obvious what's happening when the CPU goes
+ up in flames.
+ - <csr-id-c8835c6edae784c9ffcb69a674c0a6545dbb2af3/> upgrade to `prodash 21.1` and add `Ids` to all progress instances.
+ That way callers can identify progress they are interested in, say, for
+ selective visualizations.
+
+## 0.24.0 (2022-11-21)
+
+A maintenance release without user facing changes.
+
+## 0.23.1 (2022-11-06)
+
+### New Features
+
+ - <csr-id-9076ce33ec167e425a0163d3e40a81a3fd0db6cd/> `fs::Snapshot` can `Clone` if `T` can `Clone`.
+
+## 0.23.0 (2022-10-10)
+
+### New Features
+
+ - <csr-id-a7c11d2cb5f88a4ff322d9a9848459062790d8b3/> perfect granularity for threads processing with `in_parallel_with_slice()`
+ - <csr-id-ff1db66f2dad3afc8bc77610006bca9fea5947d2/> add `progress::Step|StepShared` as types of `prodash`
+ This may help to use the `Progress::counter()` method as part of method
+ signatures, being an `Option<progress::StepShared>`.
+
+### Changed (BREAKING)
+
+ - <csr-id-38446dc8824afef30ef121598de3451d13b9262c/> remove `fs-jwalk-single-threaded` in favor of `fs-walkdir-parallel`.
+ This way, `jwalk` and the dependencies (and troubles) it brings have to
+ be opted in, but also allow other users to actually opt out while
+ allowing the `parallel` feature to be in effect.
+
+ In other words, previously the `parallel` feature conflated `jwalk`
+ dependencies into the tree, which isn't the case anymore.
+
+### New Features (BREAKING)
+
+ - <csr-id-3b29fc18672c0176684c797a0f16f85d09369bf8/> make jwalk fully optional
+
+## 0.22.6 (2022-09-16)
+
+Fix docs.rs rendering.
+
+### New Features
+
+ - <csr-id-cfe46b502afc3ecb312849ddbd7748007d432cd1/> add zlib-ng feature to allow linking against system libz-ng
+ Allow to use zlib-ng (zlib-ng-sys) with native API (no compat mode)
+ that can co-exist with system libz (loaded by e.g. libcurl).
+ This is used in gitoxide package on Alpine Linux.
+
+## 0.22.5 (2022-09-20)
+
+### New Features
+
+ - <csr-id-cfe46b502afc3ecb312849ddbd7748007d432cd1/> add zlib-ng feature to allow linking against system libz-ng
+ Allow to use zlib-ng (zlib-ng-sys) with native API (no compat mode)
+ that can co-exist with system libz (loaded by e.g. libcurl).
+ This is used in gitoxide package on Alpine Linux.
+
+## 0.22.4 (2022-09-04)
+
+A maintenance release without breaking changes.
+
+## 0.22.3 (2022-08-27)
+
+### Fix
+
+- restrict `sha1` `asm` to supported archs ([`b383fab`](https://github.com/Byron/gitoxide/commit/b383fabbe10868317be51b99cfdd9b0981816042))
+
+## 0.22.2 (2022-08-24)
+
+<csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/>
+
+### Chore
+
+ - <csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/> uniformize deny attributes
+
+### New Features
+
+ - <csr-id-b1c40b0364ef092cd52d03b34f491b254816b18d/> use docsrs feature in code to show what is feature-gated automatically on docs.rs
+ - <csr-id-517677147f1c17304c62cf97a1dd09f232ebf5db/> pass --cfg docsrs when compiling for https://docs.rs
+
+## 0.22.1 (2022-08-15)
+
+### New Features
+
+ - <csr-id-f498d35baba52e40ecd47381e87c1ce49cf13285/> add `fs-jwalk-single-threaded` feature to specifically decouple `jwalk` from rayon
+ It has been an issue in https://github.com/starship/starship/issues/4251
+ apparently and rayon interactions can be difficult.
+ - <csr-id-7f199f0e5246809efde9880110093fbd11a4f8fe/> `fs::Snapshot` to on-demand reload shared resources.
+
+## 0.22.0 (2022-07-22)
+
+### New Features
+
+ - <csr-id-c76fde7de278b49ded13b655d5345e4eb8c1b134/> initialize `Time` from `now_utc` and `now_local`
+ Localtime support depends on some other factors now, but that
+ will only get better over time.
+
+ We might have to document `unsound_local_time` at some point.
+
+### Changed (BREAKING)
+
+ - <csr-id-89a41bf2b37db29b9983b4e5492cfd67ed490b23/> remove local-time-support feature toggle.
+ We treat local time as default feature without a lot of fuzz, and
+ will eventually document that definitive support needs a compile
+ time switch in the compiler (`--cfg unsound_local_offset` or something).
+
+ One day it will perish. Failure is possible anyway and we will write
+ code to deal with it while minimizing the amount of system time
+ fetches when asking for the current local time.
+
+## 0.21.1 (2022-06-13)
+
+A maintenance release without user-facing changes.
+
+## 0.21.0 (2022-05-18)
+
+### Changed (BREAKING)
+
+ - <csr-id-90611ce1527618bcc738440bfc1ccc7a45319974/> remove `path` module in favor of `gix-path` crate
+
+### New Features (BREAKING)
+
+ - <csr-id-d078d6ee76a80d1dfaf71608c12d8a402bd670d4/> mild refactor of paths module to waste less on unix
+ Previously it might have performed find-and-replace on unix paths even
+ though they wouldn't have changed afterwards, yet costing an allocation.
+
+ There is also the realization that it should go into its own crate to have
+ neater import paths and more convenience.
+
+## 0.20.0 (2022-04-02)
+
+### New Features
+
+ - <csr-id-e4d6685064ad2b433f8acd3a74b320bf0169a994/> Add `gix_config::values::Path` for a typesafe git path
+ Add a `Path` type to the `gix_config::values` which
+ can be interpolated according to gits own path interpolation
+ rules.
+ - <csr-id-3c8581fc294c65c9eb42698969fe3263135a864e/> add new 'path' module for all path-related conversions
+ It's meant to unify all path and byte related handling to help assuring
+ encoding is handled correctly or at least similarly everywhere.
+ - <csr-id-15ff212b17087de93f259e366f4e4b821cfbc28e/> in-manifest and in-lib documentation of feature toggles
+
+### Bug Fixes
+
+ - <csr-id-234cd10ca55482ce1a840ce3244308d249895bcc/> Assure std::io::copy() doesn't hang when we cause an interrupt
+ The user can ask for interruptions which previously used the
+ error kind Interrupted. This however has special meaning and
+ usually means to retry.
+
+### New Features (BREAKING)
+
+ - <csr-id-8945d95f7fa88562d37ff67ac6e38bead73dd2df/> `interrupt::Iter`, rename `interrupt::Iter` -> `interrupt::IterWithError`
+
+## 0.19.1 (2022-01-23)
+
+<csr-id-361892ca15aa648802f6701ab6a5a30aedde3449/>
+
+A maintenance release thanks to upgrade to `prodash` 18.
+
+### Changed (BREAKING)
+
+ - <csr-id-61e5cfece4d8f405e35fc1957b00ce1da7526c26/> renamed `progress::Read::reader` -> `progress::Read::inner`
+
+### New Features
+
+ - <csr-id-cb7e4e784d615f9fa3d6fb9c36240f0592403358/> Add InOrderIter to 'parallel' module
+ This iterator makes possible identifies results using a sequence id
+ and returns only consecutive items.
+
+ Use it to collect unordered results produced by threads.
+ It's advantage to collecting yourself and sorting is the potential
+ for a smaller memory footprint of in-flight results, one doesn't
+ have to collect them all for ordering, necessarily.
+ - <csr-id-ca095ed881db2a8f06a6b067dbaac17e923b0945/> Make a scope-like abstraction available
+ This allows more delicate threading control like is required for the
+ index.
+ - <csr-id-b8400ed80543d67a5895c975ba9b1fc28427411c/> decoding of variable int numbers.
+ It's here only so that we can share the code across crates, for now
+ without any feature toggles.
+ - <csr-id-0a749a22057b5513a8cefa0e26b0a9a268c769d3/> Add `progress::Write` to automatically pass bytes written to a progress instance
+
+### Chore
+
+ - <csr-id-361892ca15aa648802f6701ab6a5a30aedde3449/> update sha-1 dependency to 0.10
+
+## 0.19.0 (2022-01-19)
+
+<csr-id-361892ca15aa648802f6701ab6a5a30aedde3449/>
+
+### Chore
+
+ - <csr-id-361892ca15aa648802f6701ab6a5a30aedde3449/> update sha-1 dependency to 0.10
+
+### New Features
+
+ - <csr-id-cb7e4e784d615f9fa3d6fb9c36240f0592403358/> Add InOrderIter to 'parallel' module
+ This iterator makes possible identifies results using a sequence id
+ and returns only consecutive items.
+
+ Use it to collect unordered results produced by threads.
+ It's advantage to collecting yourself and sorting is the potential
+ for a smaller memory footprint of in-flight results, one doesn't
+ have to collect them all for ordering, necessarily.
+ - <csr-id-ca095ed881db2a8f06a6b067dbaac17e923b0945/> Make a scope-like abstraction available
+ This allows more delicate threading control like is required for the
+ index.
+ - <csr-id-b8400ed80543d67a5895c975ba9b1fc28427411c/> decoding of variable int numbers.
+ It's here only so that we can share the code across crates, for now
+ without any feature toggles.
+ - <csr-id-0a749a22057b5513a8cefa0e26b0a9a268c769d3/> Add `progress::Write` to automatically pass bytes written to a progress instance
+
+### Changed (BREAKING)
+
+ - <csr-id-61e5cfece4d8f405e35fc1957b00ce1da7526c26/> renamed `progress::Read::reader` -> `progress::Read::inner`
+
+## 0.18.0 (2021-11-29)
+
+### New Features
+
+ - <csr-id-7e95d8ab29051ffc892f2dcbaf5369e8c7e7b294/> add threading primitives with feature toggle
+ If the `threading` feature is set, the `threading` module will contain thread-safe primitives
+ for shared ownership and mutation, otherwise these will be their single threaded counterparts.
+
+ This way, single-threaded applications don't have to pay for threaded primitives.
+
+### Changed (BREAKING)
+
+ - <csr-id-e7526b2a7b51cbac4018e1ab3b623a85987fadc2/> parallel utilities now use `Send + Clone` instead of `Send + Sync`
+ This helps to assure that thread-local computations always work with the
+ kind of types we provide. The ones that are carrying out actions are
+ notably not `Sync` anymore.
+
+ We cater to that by defining our bounds accordingly, but for those
+ who want to use other utilities that need Sync, using types like
+ `Repository` and `thread_local!()` is the only way to make this
+ work.
+
+## v0.17.0 (2021-10-19)
+
+A maintenance release due to properly dealing with previously breaking changes in `gix-hash`.
+
+## v0.16.5 (2021-10-15)
+
+This release contains no functional changes.
+
+## v0.16.4 (2021-09-07)
+
+## v0.16.3 (2021-08-27)
+
+## v0.16.2 (2021-08-17)
+
+## v0.16.1 (2021-08-10)
+
+## v0.16.0 (2021-08-10)
+
+## v0.14.0 (2021-05-08)
+
+## v0.13.0 (2021-04-30)
+
+## v0.12.0 (2021-04-08)
+
+## v0.11.0 (2021-01-24)
+
+## v0.10.1 (2021-01-24)
+
+## v0.10.0 (2020-12-16)
+
+## v0.9.0 (2020-12-15)
+
+## v0.8.0 (2020-11-26)
+
+## v0.7.0 (2020-11-18)
+
+## v0.6.0 (2020-09-14)
+
+## v0.5.0 (2020-09-12)
+
+## v0.4.0 (2020-08-18)
+
+## v0.3.0 (2020-08-12)
+
+## v0.2.0 (2020-07-23)
+
+## v0.1.0 (2020-07-12)
+
+<csr-id-ab6f98b905f13ed2a7c0c483f34fab63141fbc5b/>
+
+### Other
+
+ - <csr-id-ab6f98b905f13ed2a7c0c483f34fab63141fbc5b/> try-join with static typing works, but…
+ …seems like a lot of effort. Probably not worth continuing here
+
diff --git a/vendor/gix-features/Cargo.toml b/vendor/gix-features/Cargo.toml
new file mode 100644
index 000000000..906a114ed
--- /dev/null
+++ b/vendor/gix-features/Cargo.toml
@@ -0,0 +1,180 @@
+# 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.64"
+name = "gix-features"
+version = "0.28.0"
+authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>"]
+description = "A crate to integrate various capabilities using compile-time feature flags"
+license = "MIT/Apache-2.0"
+repository = "https://github.com/Byron/gitoxide"
+resolver = "2"
+
+[package.metadata.docs.rs]
+all-features = true
+features = ["document-features"]
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+]
+
+[lib]
+test = false
+doctest = false
+
+[[test]]
+name = "hash"
+path = "tests/hash.rs"
+required-features = ["rustsha1"]
+
+[[test]]
+name = "parallel"
+path = "tests/parallel_threaded.rs"
+required-features = [
+ "parallel",
+ "rustsha1",
+]
+
+[[test]]
+name = "multi-threaded"
+path = "tests/parallel_shared_threaded.rs"
+required-features = [
+ "parallel",
+ "rustsha1",
+]
+
+[[test]]
+name = "single-threaded"
+path = "tests/parallel_shared.rs"
+required-features = ["rustsha1"]
+
+[[test]]
+name = "pipe"
+path = "tests/pipe.rs"
+required-features = ["io-pipe"]
+
+[dependencies.bytes]
+version = "1.0.0"
+optional = true
+
+[dependencies.bytesize]
+version = "1.0.1"
+optional = true
+
+[dependencies.crc32fast]
+version = "1.2.1"
+optional = true
+
+[dependencies.crossbeam-channel]
+version = "0.5.0"
+optional = true
+
+[dependencies.document-features]
+version = "0.2.0"
+optional = true
+
+[dependencies.flate2]
+version = "1.0.17"
+optional = true
+default-features = false
+
+[dependencies.gix-hash]
+version = "^0.10.3"
+
+[dependencies.jwalk]
+version = "0.8.1"
+optional = true
+
+[dependencies.once_cell]
+version = "1.13.0"
+optional = true
+
+[dependencies.parking_lot]
+version = "0.12.0"
+optional = true
+default-features = false
+
+[dependencies.prodash]
+version = "23.1"
+optional = true
+default-features = false
+
+[dependencies.sha1]
+version = "0.10.0"
+optional = true
+
+[dependencies.sha1_smol]
+version = "1.0.0"
+optional = true
+
+[dependencies.thiserror]
+version = "1.0.38"
+optional = true
+
+[dependencies.walkdir]
+version = "2.3.2"
+optional = true
+
+[dev-dependencies.bstr]
+version = "1.3.0"
+default-features = false
+
+[features]
+cache-efficiency-debug = []
+crc32 = ["dep:crc32fast"]
+default = []
+fast-sha1 = ["dep:sha1"]
+fs-walkdir-parallel = ["dep:jwalk"]
+io-pipe = ["dep:bytes"]
+once_cell = ["dep:once_cell"]
+parallel = [
+ "dep:crossbeam-channel",
+ "dep:parking_lot",
+]
+progress = ["dep:prodash"]
+progress-unit-bytes = [
+ "dep:bytesize",
+ "prodash?/unit-bytes",
+]
+progress-unit-human-numbers = ["prodash?/unit-human"]
+rustsha1 = ["dep:sha1_smol"]
+walkdir = ["dep:walkdir"]
+zlib = [
+ "dep:flate2",
+ "flate2?/rust_backend",
+ "dep:thiserror",
+]
+zlib-ng = [
+ "zlib",
+ "flate2?/zlib-ng",
+]
+zlib-ng-compat = [
+ "zlib",
+ "flate2?/zlib-ng-compat",
+]
+zlib-rust-backend = [
+ "zlib",
+ "flate2?/rust_backend",
+]
+zlib-stock = [
+ "zlib",
+ "flate2?/zlib",
+]
+
+[target."cfg(all(any(target_arch = \"aarch64\", target_arch = \"x86\", target_arch = \"x86_64\"), not(target_env = \"msvc\")))".dependencies.sha1]
+version = "0.10.0"
+features = ["asm"]
+optional = true
+
+[target."cfg(unix)".dependencies.libc]
+version = "0.2.119"
diff --git a/vendor/gix-features/src/cache.rs b/vendor/gix-features/src/cache.rs
new file mode 100644
index 000000000..f7a2cf005
--- /dev/null
+++ b/vendor/gix-features/src/cache.rs
@@ -0,0 +1,76 @@
+#[cfg(feature = "cache-efficiency-debug")]
+mod impl_ {
+ /// A helper to collect useful information about cache efficiency.
+ pub struct Debug {
+ owner: String,
+ hits: usize,
+ puts: usize,
+ misses: usize,
+ }
+
+ impl Debug {
+ /// Create a new instance
+ #[inline]
+ pub fn new(owner: impl Into<String>) -> Self {
+ Debug {
+ owner: owner.into(),
+ hits: 0,
+ puts: 0,
+ misses: 0,
+ }
+ }
+ /// Count cache insertions
+ #[inline]
+ pub fn put(&mut self) {
+ self.puts += 1;
+ }
+ /// Count hits
+ #[inline]
+ pub fn hit(&mut self) {
+ self.hits += 1;
+ }
+ /// Count misses
+ #[inline]
+ pub fn miss(&mut self) {
+ self.misses += 1;
+ }
+ }
+
+ impl Drop for Debug {
+ fn drop(&mut self) {
+ let hits = self.hits;
+ let misses = self.misses;
+ let ratio = hits as f32 / misses as f32;
+ eprintln!(
+ "{}[{:0x}]: {} / {} (hits/misses) = {:.02}%, puts = {}",
+ self.owner,
+ self as *const _ as usize,
+ hits,
+ misses,
+ ratio * 100.0,
+ self.puts
+ );
+ }
+ }
+}
+#[cfg(not(feature = "cache-efficiency-debug"))]
+mod impl_ {
+ /// The disabled, zero size do-nothing equivalent
+ pub struct Debug;
+
+ impl Debug {
+ /// Create a new instance
+ #[inline]
+ pub fn new(_owner: impl Into<String>) -> Self {
+ Debug
+ }
+ /// noop
+ pub fn put(&mut self) {}
+ /// noop
+ pub fn hit(&mut self) {}
+ /// noop
+ pub fn miss(&mut self) {}
+ }
+}
+
+pub use impl_::Debug;
diff --git a/vendor/gix-features/src/decode.rs b/vendor/gix-features/src/decode.rs
new file mode 100644
index 000000000..0df38710d
--- /dev/null
+++ b/vendor/gix-features/src/decode.rs
@@ -0,0 +1,38 @@
+use std::io::Read;
+
+/// Decode variable int numbers from a `Read` implementation.
+///
+/// Note: currently overflow checks are only done in debug mode.
+#[inline]
+pub fn leb64_from_read(mut r: impl Read) -> Result<(u64, usize), std::io::Error> {
+ let mut b = [0u8; 1];
+ let mut i = 0;
+ r.read_exact(&mut b)?;
+ i += 1;
+ let mut value = b[0] as u64 & 0x7f;
+ while b[0] & 0x80 != 0 {
+ r.read_exact(&mut b)?;
+ i += 1;
+ debug_assert!(i <= 10, "Would overflow value at 11th iteration");
+ value += 1;
+ value = (value << 7) + (b[0] as u64 & 0x7f)
+ }
+ Ok((value, i))
+}
+
+/// Decode variable int numbers.
+#[inline]
+pub fn leb64(d: &[u8]) -> (u64, usize) {
+ let mut i = 0;
+ let mut c = d[i];
+ i += 1;
+ let mut value = c as u64 & 0x7f;
+ while c & 0x80 != 0 {
+ c = d[i];
+ i += 1;
+ debug_assert!(i <= 10, "Would overflow value at 11th iteration");
+ value += 1;
+ value = (value << 7) + (c as u64 & 0x7f)
+ }
+ (value, i)
+}
diff --git a/vendor/gix-features/src/fs.rs b/vendor/gix-features/src/fs.rs
new file mode 100644
index 000000000..f65779b92
--- /dev/null
+++ b/vendor/gix-features/src/fs.rs
@@ -0,0 +1,246 @@
+//! Filesystem utilities
+//!
+//! These are will be parallel if the `parallel` feature is enabled, at the expense of compiling additional dependencies
+//! along with runtime costs for maintaining a global [`rayon`](https://docs.rs/rayon) thread pool.
+//!
+//! For information on how to use the [`WalkDir`] type, have a look at
+//! * [`jwalk::WalkDir`](https://docs.rs/jwalk/0.5.1/jwalk/type.WalkDir.html) if `parallel` feature is enabled
+//! * [walkdir::WalkDir](https://docs.rs/walkdir/2.3.1/walkdir/struct.WalkDir.html) otherwise
+
+#[cfg(any(feature = "walkdir", feature = "fs-walkdir-parallel"))]
+mod shared {
+ /// The desired level of parallelism.
+ pub enum Parallelism {
+ /// Do not parallelize at all by making a serial traversal on the current thread.
+ Serial,
+ /// Create a new thread pool for each traversal with up to 16 threads or the amount of logical cores of the machine.
+ ThreadPoolPerTraversal {
+ /// The base name of the threads we create as part of the thread-pool.
+ thread_name: &'static str,
+ },
+ }
+}
+
+///
+#[cfg(feature = "fs-walkdir-parallel")]
+pub mod walkdir {
+ use std::path::Path;
+
+ pub use jwalk::{DirEntry as DirEntryGeneric, DirEntryIter as DirEntryIterGeneric, Error, WalkDir};
+
+ pub use super::shared::Parallelism;
+
+ /// An alias for an uncustomized directory entry to match the one of the non-parallel version offered by `walkdir`.
+ pub type DirEntry = DirEntryGeneric<((), ())>;
+
+ impl From<Parallelism> for jwalk::Parallelism {
+ fn from(v: Parallelism) -> Self {
+ match v {
+ Parallelism::Serial => jwalk::Parallelism::Serial,
+ Parallelism::ThreadPoolPerTraversal { thread_name } => std::thread::available_parallelism()
+ .map(|threads| {
+ let pool = jwalk::rayon::ThreadPoolBuilder::new()
+ .num_threads(threads.get().min(16))
+ .stack_size(128 * 1024)
+ .thread_name(move |idx| format!("{thread_name} {idx}"))
+ .build()
+ .expect("we only set options that can't cause a build failure");
+ jwalk::Parallelism::RayonExistingPool {
+ pool: pool.into(),
+ busy_timeout: None,
+ }
+ })
+ .unwrap_or_else(|_| Parallelism::Serial.into()),
+ }
+ }
+ }
+
+ /// Instantiate a new directory iterator which will not skip hidden files, with the given level of `parallelism`.
+ pub fn walkdir_new(root: impl AsRef<Path>, parallelism: Parallelism) -> WalkDir {
+ WalkDir::new(root).skip_hidden(false).parallelism(parallelism.into())
+ }
+
+ /// Instantiate a new directory iterator which will not skip hidden files and is sorted
+ pub fn walkdir_sorted_new(root: impl AsRef<Path>, parallelism: Parallelism) -> WalkDir {
+ WalkDir::new(root)
+ .skip_hidden(false)
+ .sort(true)
+ .parallelism(parallelism.into())
+ }
+
+ /// The Iterator yielding directory items
+ pub type DirEntryIter = DirEntryIterGeneric<((), ())>;
+}
+
+#[cfg(all(feature = "walkdir", not(feature = "fs-walkdir-parallel")))]
+///
+pub mod walkdir {
+ use std::path::Path;
+
+ pub use walkdir::{DirEntry, Error, WalkDir};
+
+ pub use super::shared::Parallelism;
+
+ /// Instantiate a new directory iterator which will not skip hidden files, with the given level of `parallelism`.
+ pub fn walkdir_new(root: impl AsRef<Path>, _: Parallelism) -> WalkDir {
+ WalkDir::new(root)
+ }
+
+ /// Instantiate a new directory iterator which will not skip hidden files and is sorted, with the given level of `parallelism`.
+ pub fn walkdir_sorted_new(root: impl AsRef<Path>, _: Parallelism) -> WalkDir {
+ WalkDir::new(root).sort_by_file_name()
+ }
+
+ /// The Iterator yielding directory items
+ pub type DirEntryIter = walkdir::IntoIter;
+}
+
+#[cfg(any(feature = "walkdir", feature = "fs-walkdir-parallel"))]
+pub use self::walkdir::{walkdir_new, walkdir_sorted_new, WalkDir};
+
+/// Prepare open options which won't follow symlinks when the file is opened.
+///
+/// Note: only effective on unix currently.
+pub fn open_options_no_follow() -> std::fs::OpenOptions {
+ #[cfg_attr(not(unix), allow(unused_mut))]
+ let mut options = std::fs::OpenOptions::new();
+ #[cfg(unix)]
+ {
+ /// Make sure that it's impossible to follow through to the target of symlinks.
+ /// Note that this will still follow symlinks in the path, which is what we assume
+ /// has been checked separately.
+ use std::os::unix::fs::OpenOptionsExt;
+ options.custom_flags(libc::O_NOFOLLOW);
+ }
+ options
+}
+
+mod snapshot {
+ use std::ops::Deref;
+
+ use crate::threading::{get_mut, get_ref, MutableOnDemand, OwnShared};
+
+ /// A structure holding enough information to reload a value if its on-disk representation changes as determined by its modified time.
+ #[derive(Debug)]
+ pub struct Snapshot<T: std::fmt::Debug> {
+ value: T,
+ modified: std::time::SystemTime,
+ }
+
+ impl<T: Clone + std::fmt::Debug> Clone for Snapshot<T> {
+ fn clone(&self) -> Self {
+ Self {
+ value: self.value.clone(),
+ modified: self.modified,
+ }
+ }
+ }
+
+ /// A snapshot of a resource which is up-to-date in the moment it is retrieved.
+ pub type SharedSnapshot<T> = OwnShared<Snapshot<T>>;
+
+ /// Use this type for fields in structs that are to store the [`Snapshot`], typically behind an [`OwnShared`].
+ ///
+ /// Note that the resource itself is behind another [`OwnShared`] to allow it to be used without holding any kind of lock, hence
+ /// without blocking updates while it is used.
+ #[derive(Debug, Default)]
+ pub struct MutableSnapshot<T: std::fmt::Debug>(pub MutableOnDemand<Option<SharedSnapshot<T>>>);
+
+ impl<T: std::fmt::Debug> Deref for Snapshot<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+ }
+
+ impl<T: std::fmt::Debug> Deref for MutableSnapshot<T> {
+ type Target = MutableOnDemand<Option<SharedSnapshot<T>>>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+
+ impl<T: std::fmt::Debug> MutableSnapshot<T> {
+ /// Create a new instance of this type.
+ ///
+ /// Useful in case `Default::default()` isn't working for some reason.
+ pub fn new() -> Self {
+ MutableSnapshot(MutableOnDemand::new(None))
+ }
+
+ /// Refresh `state` forcefully by re-`open`ing the resource. Note that `open()` returns `None` if the resource isn't
+ /// present on disk, and that it's critical that the modified time is obtained _before_ opening the resource.
+ pub fn force_refresh<E>(
+ &self,
+ open: impl FnOnce() -> Result<Option<(std::time::SystemTime, T)>, E>,
+ ) -> Result<(), E> {
+ let mut state = get_mut(&self.0);
+ *state = open()?.map(|(modified, value)| OwnShared::new(Snapshot { value, modified }));
+ Ok(())
+ }
+
+ /// Assure that the resource in `state` is up-to-date by comparing the `current_modification_time` with the one we know in `state`
+ /// and by acting accordingly.
+ /// Returns the potentially updated/reloaded resource if it is still present on disk, which then represents a snapshot that is up-to-date
+ /// in that very moment, or `None` if the underlying file doesn't exist.
+ ///
+ /// Note that even though this is racy, each time a request is made there is a chance to see the actual state.
+ pub fn recent_snapshot<E>(
+ &self,
+ mut current_modification_time: impl FnMut() -> Option<std::time::SystemTime>,
+ open: impl FnOnce() -> Result<Option<T>, E>,
+ ) -> Result<Option<SharedSnapshot<T>>, E> {
+ let state = get_ref(self);
+ let recent_modification = current_modification_time();
+ let buffer = match (&*state, recent_modification) {
+ (None, None) => (*state).clone(),
+ (Some(_), None) => {
+ drop(state);
+ let mut state = get_mut(self);
+ *state = None;
+ (*state).clone()
+ }
+ (Some(snapshot), Some(modified_time)) => {
+ if snapshot.modified < modified_time {
+ drop(state);
+ let mut state = get_mut(self);
+
+ if let (Some(_snapshot), Some(modified_time)) = (&*state, current_modification_time()) {
+ *state = open()?.map(|value| {
+ OwnShared::new(Snapshot {
+ value,
+ modified: modified_time,
+ })
+ });
+ }
+
+ (*state).clone()
+ } else {
+ // Note that this relies on sub-section precision or else is a race when the packed file was just changed.
+ // It's nothing we can know though, so… up to the caller unfortunately.
+ Some(snapshot.clone())
+ }
+ }
+ (None, Some(_modified_time)) => {
+ drop(state);
+ let mut state = get_mut(self);
+ // Still in the same situation? If so, load the buffer. This compensates for the trampling herd
+ // during lazy-loading at the expense of another mtime check.
+ if let (None, Some(modified_time)) = (&*state, current_modification_time()) {
+ *state = open()?.map(|value| {
+ OwnShared::new(Snapshot {
+ value,
+ modified: modified_time,
+ })
+ });
+ }
+ (*state).clone()
+ }
+ };
+ Ok(buffer)
+ }
+ }
+}
+pub use snapshot::{MutableSnapshot, SharedSnapshot, Snapshot};
diff --git a/vendor/gix-features/src/hash.rs b/vendor/gix-features/src/hash.rs
new file mode 100644
index 000000000..fe064139a
--- /dev/null
+++ b/vendor/gix-features/src/hash.rs
@@ -0,0 +1,190 @@
+//! Hash functions and hash utilities
+//!
+//! With the `fast-sha1` feature, the `Sha1` hash type will use a more elaborate implementation utilizing hardware support
+//! in case it is available. Otherwise the `rustsha1` feature should be set. `fast-sha1` will take precedence.
+//! Otherwise, a minimal yet performant implementation is used instead for a decent trade-off between compile times and run-time performance.
+#[cfg(all(feature = "rustsha1", not(feature = "fast-sha1")))]
+mod _impl {
+ use super::Sha1Digest;
+
+ /// A implementation of the Sha1 hash, which can be used once.
+ #[derive(Default, Clone)]
+ pub struct Sha1(sha1_smol::Sha1);
+
+ impl Sha1 {
+ /// Digest the given `bytes`.
+ pub fn update(&mut self, bytes: &[u8]) {
+ self.0.update(bytes)
+ }
+ /// Finalize the hash and produce a digest.
+ pub fn digest(self) -> Sha1Digest {
+ self.0.digest().bytes()
+ }
+ }
+}
+
+/// A 20 bytes digest produced by a [`Sha1`] hash implementation.
+#[cfg(any(feature = "fast-sha1", feature = "rustsha1"))]
+pub type Sha1Digest = [u8; 20];
+
+#[cfg(feature = "fast-sha1")]
+mod _impl {
+ use sha1::Digest;
+
+ use super::Sha1Digest;
+
+ /// A implementation of the Sha1 hash, which can be used once.
+ #[derive(Default, Clone)]
+ pub struct Sha1(sha1::Sha1);
+
+ impl Sha1 {
+ /// Digest the given `bytes`.
+ pub fn update(&mut self, bytes: &[u8]) {
+ self.0.update(bytes)
+ }
+ /// Finalize the hash and produce a digest.
+ pub fn digest(self) -> Sha1Digest {
+ self.0.finalize().into()
+ }
+ }
+}
+
+#[cfg(any(feature = "rustsha1", feature = "fast-sha1"))]
+pub use _impl::Sha1;
+
+/// Compute a CRC32 hash from the given `bytes`, returning the CRC32 hash.
+///
+/// When calling this function for the first time, `previous_value` should be `0`. Otherwise it
+/// should be the previous return value of this function to provide a hash of multiple sequential
+/// chunks of `bytes`.
+#[cfg(feature = "crc32")]
+pub fn crc32_update(previous_value: u32, bytes: &[u8]) -> u32 {
+ let mut h = crc32fast::Hasher::new_with_initial(previous_value);
+ h.update(bytes);
+ h.finalize()
+}
+
+/// Compute a CRC32 value of the given input `bytes`.
+///
+/// In case multiple chunks of `bytes` are present, one should use [`crc32_update()`] instead.
+#[cfg(feature = "crc32")]
+pub fn crc32(bytes: &[u8]) -> u32 {
+ let mut h = crc32fast::Hasher::new();
+ h.update(bytes);
+ h.finalize()
+}
+
+/// Produce a hasher suitable for the given kind of hash.
+#[cfg(any(feature = "rustsha1", feature = "fast-sha1"))]
+pub fn hasher(kind: gix_hash::Kind) -> Sha1 {
+ match kind {
+ gix_hash::Kind::Sha1 => Sha1::default(),
+ }
+}
+
+/// Compute the hash of `kind` for the bytes in the file at `path`, hashing only the first `num_bytes_from_start`
+/// while initializing and calling `progress`.
+///
+/// `num_bytes_from_start` is useful to avoid reading trailing hashes, which are never part of the hash itself,
+/// denoting the amount of bytes to hash starting from the beginning of the file.
+///
+/// # Note
+///
+/// * Only available with the `gix-object` feature enabled due to usage of the [`gix_hash::Kind`] enum and the
+/// [`gix_hash::ObjectId`] return value.
+/// * [Interrupts][crate::interrupt] are supported.
+#[cfg(all(feature = "progress", any(feature = "rustsha1", feature = "fast-sha1")))]
+pub fn bytes_of_file(
+ path: impl AsRef<std::path::Path>,
+ num_bytes_from_start: usize,
+ kind: gix_hash::Kind,
+ progress: &mut impl crate::progress::Progress,
+ should_interrupt: &std::sync::atomic::AtomicBool,
+) -> std::io::Result<gix_hash::ObjectId> {
+ bytes(
+ std::fs::File::open(path)?,
+ num_bytes_from_start,
+ kind,
+ progress,
+ should_interrupt,
+ )
+}
+
+/// Similar to [`bytes_of_file`], but operates on an already open file.
+#[cfg(all(feature = "progress", any(feature = "rustsha1", feature = "fast-sha1")))]
+pub fn bytes(
+ mut read: impl std::io::Read,
+ num_bytes_from_start: usize,
+ kind: gix_hash::Kind,
+ progress: &mut impl crate::progress::Progress,
+ should_interrupt: &std::sync::atomic::AtomicBool,
+) -> std::io::Result<gix_hash::ObjectId> {
+ let mut hasher = hasher(kind);
+ let start = std::time::Instant::now();
+ // init progress before the possibility for failure, as convenience in case people want to recover
+ progress.init(Some(num_bytes_from_start), crate::progress::bytes());
+
+ const BUF_SIZE: usize = u16::MAX as usize;
+ let mut buf = [0u8; BUF_SIZE];
+ let mut bytes_left = num_bytes_from_start;
+
+ while bytes_left > 0 {
+ let out = &mut buf[..BUF_SIZE.min(bytes_left)];
+ read.read_exact(out)?;
+ bytes_left -= out.len();
+ progress.inc_by(out.len());
+ hasher.update(out);
+ if should_interrupt.load(std::sync::atomic::Ordering::SeqCst) {
+ return Err(std::io::Error::new(std::io::ErrorKind::Other, "Interrupted"));
+ }
+ }
+
+ let id = gix_hash::ObjectId::from(hasher.digest());
+ progress.show_throughput(start);
+ Ok(id)
+}
+
+#[cfg(any(feature = "rustsha1", feature = "fast-sha1"))]
+mod write {
+ use crate::hash::Sha1;
+
+ /// A utility to automatically generate a hash while writing into an inner writer.
+ pub struct Write<T> {
+ /// The hash implementation.
+ pub hash: Sha1,
+ /// The inner writer.
+ pub inner: T,
+ }
+
+ impl<T> std::io::Write for Write<T>
+ where
+ T: std::io::Write,
+ {
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ let written = self.inner.write(buf)?;
+ self.hash.update(&buf[..written]);
+ Ok(written)
+ }
+
+ fn flush(&mut self) -> std::io::Result<()> {
+ self.inner.flush()
+ }
+ }
+
+ impl<T> Write<T>
+ where
+ T: std::io::Write,
+ {
+ /// Create a new hash writer which hashes all bytes written to `inner` with a hash of `kind`.
+ pub fn new(inner: T, object_hash: gix_hash::Kind) -> Self {
+ match object_hash {
+ gix_hash::Kind::Sha1 => Write {
+ inner,
+ hash: Sha1::default(),
+ },
+ }
+ }
+ }
+}
+#[cfg(any(feature = "rustsha1", feature = "fast-sha1"))]
+pub use write::Write;
diff --git a/vendor/gix-features/src/interrupt.rs b/vendor/gix-features/src/interrupt.rs
new file mode 100644
index 000000000..1f78e613a
--- /dev/null
+++ b/vendor/gix-features/src/interrupt.rs
@@ -0,0 +1,125 @@
+//! Utilities to cause interruptions in common traits, like Read/Write and Iterator.
+use std::{
+ io,
+ sync::atomic::{AtomicBool, Ordering},
+};
+
+/// A wrapper for an inner iterator which will check for interruptions on each iteration, stopping the iteration when
+/// that is requested.
+pub struct Iter<'a, I> {
+ /// The actual iterator to yield elements from.
+ pub inner: I,
+ should_interrupt: &'a AtomicBool,
+}
+
+impl<'a, I> Iter<'a, I>
+where
+ I: Iterator,
+{
+ /// Create a new iterator over `inner` which checks for interruptions on each iteration on `should_interrupt`.
+ ///
+ /// Note that this means the consumer of the iterator data should also be able to access `should_interrupt` and
+ /// consider it when producing the final result to avoid claiming success even though the operation is only partially
+ /// complete.
+ pub fn new(inner: I, should_interrupt: &'a AtomicBool) -> Self {
+ Iter {
+ inner,
+ should_interrupt,
+ }
+ }
+}
+
+impl<'a, I> Iterator for Iter<'a, I>
+where
+ I: Iterator,
+{
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.should_interrupt.load(Ordering::Relaxed) {
+ return None;
+ }
+ self.inner.next()
+ }
+}
+
+/// A wrapper for an inner iterator which will check for interruptions on each iteration.
+pub struct IterWithErr<'a, I, EFN> {
+ /// The actual iterator to yield elements from.
+ pub inner: I,
+ make_err: Option<EFN>,
+ should_interrupt: &'a AtomicBool,
+}
+
+impl<'a, I, EFN, E> IterWithErr<'a, I, EFN>
+where
+ I: Iterator,
+ EFN: FnOnce() -> E,
+{
+ /// Create a new iterator over `inner` which checks for interruptions on each iteration and calls `make_err()` to
+ /// signal an interruption happened, causing no further items to be iterated from that point on.
+ pub fn new(inner: I, make_err: EFN, should_interrupt: &'a AtomicBool) -> Self {
+ IterWithErr {
+ inner,
+ make_err: Some(make_err),
+ should_interrupt,
+ }
+ }
+}
+
+impl<'a, I, EFN, E> Iterator for IterWithErr<'a, I, EFN>
+where
+ I: Iterator,
+ EFN: FnOnce() -> E,
+{
+ type Item = Result<I::Item, E>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.make_err.as_ref()?;
+ if self.should_interrupt.load(Ordering::Relaxed) {
+ return self.make_err.take().map(|f| Err(f()));
+ }
+ match self.inner.next() {
+ Some(next) => Some(Ok(next)),
+ None => {
+ self.make_err = None;
+ None
+ }
+ }
+ }
+}
+
+/// A wrapper for implementors of [`std::io::Read`] or [`std::io::BufRead`] with interrupt support.
+///
+/// It fails a [read][`std::io::Read::read`] while an interrupt was requested.
+pub struct Read<'a, R> {
+ /// The actual implementor of [`std::io::Read`] to which interrupt support will be added.
+ pub inner: R,
+ /// The flag to trigger interruption
+ pub should_interrupt: &'a AtomicBool,
+}
+
+impl<'a, R> io::Read for Read<'a, R>
+where
+ R: io::Read,
+{
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ if self.should_interrupt.load(Ordering::Relaxed) {
+ return Err(std::io::Error::new(std::io::ErrorKind::Other, "Interrupted"));
+ }
+ self.inner.read(buf)
+ }
+}
+
+impl<'a, R> io::BufRead for Read<'a, R>
+where
+ R: io::BufRead,
+{
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ self.inner.fill_buf()
+ }
+
+ fn consume(&mut self, amt: usize) {
+ self.inner.consume(amt)
+ }
+}
diff --git a/vendor/gix-features/src/io.rs b/vendor/gix-features/src/io.rs
new file mode 100644
index 000000000..405960c0b
--- /dev/null
+++ b/vendor/gix-features/src/io.rs
@@ -0,0 +1,94 @@
+//!A unidirectional pipe for bytes, analogous to a unix pipe. Available with the `io-pipe` feature toggle.
+
+/// A unidirectional pipe for bytes, analogous to a unix pipe. Available with the `io-pipe` feature toggle.
+#[cfg(feature = "io-pipe")]
+pub mod pipe {
+ use std::io;
+
+ use bytes::{Buf, BufMut, BytesMut};
+
+ /// The write-end of the pipe, receiving items to become available in the [`Reader`].
+ ///
+ /// It's commonly used with the [`std::io::Write`] trait it implements.
+ pub struct Writer {
+ /// The channel through which bytes are transferred. Useful for sending [`std::io::Error`]s instead.
+ pub channel: std::sync::mpsc::SyncSender<io::Result<BytesMut>>,
+ buf: BytesMut,
+ }
+
+ /// The read-end of the pipe, implementing the [`std::io::Read`] trait.
+ pub struct Reader {
+ channel: std::sync::mpsc::Receiver<io::Result<BytesMut>>,
+ buf: BytesMut,
+ }
+
+ impl io::BufRead for Reader {
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ if self.buf.is_empty() {
+ match self.channel.recv() {
+ Ok(Ok(buf)) => self.buf = buf,
+ Ok(Err(err)) => return Err(err),
+ Err(_) => {}
+ }
+ };
+ Ok(&self.buf)
+ }
+
+ fn consume(&mut self, amt: usize) {
+ self.buf.advance(amt.min(self.buf.len()));
+ }
+ }
+
+ impl io::Read for Reader {
+ fn read(&mut self, mut out: &mut [u8]) -> io::Result<usize> {
+ let mut written = 0;
+ while !out.is_empty() {
+ if self.buf.is_empty() {
+ match self.channel.recv() {
+ Ok(Ok(buf)) => self.buf = buf,
+ Ok(Err(err)) => return Err(err),
+ Err(_) => break,
+ }
+ }
+ let bytes_to_write = self.buf.len().min(out.len());
+ let (to_write, rest) = out.split_at_mut(bytes_to_write);
+ self.buf.split_to(bytes_to_write).copy_to_slice(to_write);
+ out = rest;
+ written += bytes_to_write;
+ }
+ Ok(written)
+ }
+ }
+
+ impl io::Write for Writer {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.buf.put_slice(buf);
+ self.channel
+ .send(Ok(self.buf.split()))
+ .map_err(|err| io::Error::new(io::ErrorKind::BrokenPipe, err))?;
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+ }
+
+ /// Returns the _([`write`][Writer], [`read`][Reader])_ ends of a pipe for transferring bytes, analogous to a unix pipe.
+ ///
+ /// * `in_flight_writes` defines the amount of chunks of bytes to keep in memory until the `write` end will block when writing.
+ /// If `None` or `0`, the `write` end will always block until the `read` end consumes the transferred bytes.
+ pub fn unidirectional(in_flight_writes: impl Into<Option<usize>>) -> (Writer, Reader) {
+ let (tx, rx) = std::sync::mpsc::sync_channel(in_flight_writes.into().unwrap_or(0));
+ (
+ Writer {
+ channel: tx,
+ buf: BytesMut::with_capacity(4096),
+ },
+ Reader {
+ channel: rx,
+ buf: BytesMut::new(),
+ },
+ )
+ }
+}
diff --git a/vendor/gix-features/src/lib.rs b/vendor/gix-features/src/lib.rs
new file mode 100644
index 000000000..643320c0f
--- /dev/null
+++ b/vendor/gix-features/src/lib.rs
@@ -0,0 +1,64 @@
+//! A crate providing foundational capabilities to other `git-*` crates with trade-offs between compile time, binary size or speed
+//! selectable using cargo feature toggles.
+//!
+//! It's designed to allow the application level crate to configure feature toggles, affecting all other `git-*` crates using
+//! this one.
+//!
+//! Thus all features provided here commonly have a 'cheap' base implementation, with the option to pull in
+//! counterparts with higher performance.
+//! ## Feature Flags
+#![cfg_attr(
+ feature = "document-features",
+ cfg_attr(doc, doc = ::document_features::document_features!())
+)]
+#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
+#![deny(missing_docs, rust_2018_idioms, unsafe_code)]
+
+///
+pub mod cache;
+///
+pub mod decode;
+pub mod fs;
+pub mod hash;
+pub mod interrupt;
+#[cfg(feature = "io-pipe")]
+pub mod io;
+pub mod parallel;
+#[cfg(feature = "progress")]
+pub mod progress;
+pub mod threading;
+///
+#[cfg(feature = "zlib")]
+pub mod zlib;
+
+///
+pub mod iter {
+ /// An iterator over chunks of input, producing `Vec<Item>` with a size of `size`, with the last chunk being the remainder and thus
+ /// potentially smaller than `size`.
+ pub struct Chunks<I> {
+ /// The inner iterator to ask for items.
+ pub inner: I,
+ /// The size of chunks to produce
+ pub size: usize,
+ }
+
+ impl<I, Item> Iterator for Chunks<I>
+ where
+ I: Iterator<Item = Item>,
+ {
+ type Item = Vec<Item>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let mut res = Vec::with_capacity(self.size);
+ let mut items_left = self.size;
+ for item in &mut self.inner {
+ res.push(item);
+ items_left -= 1;
+ if items_left == 0 {
+ break;
+ }
+ }
+ (!res.is_empty()).then_some(res)
+ }
+ }
+}
diff --git a/vendor/gix-features/src/parallel/eager_iter.rs b/vendor/gix-features/src/parallel/eager_iter.rs
new file mode 100644
index 000000000..60123f54c
--- /dev/null
+++ b/vendor/gix-features/src/parallel/eager_iter.rs
@@ -0,0 +1,124 @@
+/// Evaluate any iterator in their own thread.
+///
+/// This is particularly useful if the wrapped iterator performs IO and/or heavy computations.
+/// Use [`EagerIter::new()`] for instantiation.
+pub struct EagerIter<I: Iterator> {
+ receiver: std::sync::mpsc::Receiver<Vec<I::Item>>,
+ chunk: Option<std::vec::IntoIter<I::Item>>,
+ size_hint: (usize, Option<usize>),
+}
+
+impl<I> EagerIter<I>
+where
+ I: Iterator + Send + 'static,
+ <I as Iterator>::Item: Send,
+{
+ /// Return a new `EagerIter` which evaluates `iter` in its own thread,
+ /// with a given `chunk_size` allowing a maximum `chunks_in_flight`.
+ ///
+ /// * `chunk_size` describes how many items returned by `iter` will be a single item of this `EagerIter`.
+ /// This helps to reduce the overhead imposed by transferring many small items.
+ /// If this number is 1, each item will become a single chunk. 0 is invalid.
+ /// * `chunks_in_flight` describes how many chunks can be kept in memory in case the consumer of the `EagerIter`s items
+ /// isn't consuming them fast enough. Setting this number to 0 effectively turns off any caching, but blocks `EagerIter`
+ /// if its items aren't consumed fast enough.
+ pub fn new(iter: I, chunk_size: usize, chunks_in_flight: usize) -> Self {
+ let (sender, receiver) = std::sync::mpsc::sync_channel(chunks_in_flight);
+ let size_hint = iter.size_hint();
+ assert!(chunk_size > 0, "non-zero chunk size is needed");
+
+ std::thread::spawn(move || {
+ let mut out = Vec::with_capacity(chunk_size);
+ for item in iter {
+ out.push(item);
+ if out.len() == chunk_size {
+ if sender.send(out).is_err() {
+ return;
+ }
+ out = Vec::with_capacity(chunk_size);
+ }
+ }
+ if !out.is_empty() {
+ sender.send(out).ok();
+ }
+ });
+ EagerIter {
+ receiver,
+ chunk: None,
+ size_hint,
+ }
+ }
+
+ fn fill_buf_and_pop(&mut self) -> Option<I::Item> {
+ self.chunk = self.receiver.recv().ok().map(|v| {
+ assert!(!v.is_empty());
+ v.into_iter()
+ });
+ self.chunk.as_mut().and_then(|c| c.next())
+ }
+}
+
+impl<I> Iterator for EagerIter<I>
+where
+ I: Iterator + Send + 'static,
+ <I as Iterator>::Item: Send,
+{
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.chunk.as_mut() {
+ Some(chunk) => chunk.next().or_else(|| self.fill_buf_and_pop()),
+ None => self.fill_buf_and_pop(),
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.size_hint
+ }
+}
+
+/// An conditional `EagerIter`, which may become a just-in-time iterator running in the main thread depending on a condition.
+pub enum EagerIterIf<I: Iterator> {
+ /// A separate thread will eagerly evaluate iterator `I`.
+ Eager(EagerIter<I>),
+ /// The current thread evaluates `I`.
+ OnDemand(I),
+}
+
+impl<I> EagerIterIf<I>
+where
+ I: Iterator + Send + 'static,
+ <I as Iterator>::Item: Send,
+{
+ /// Return a new `EagerIterIf` if `condition()` returns true.
+ ///
+ /// For all other parameters, please see [`EagerIter::new()`].
+ pub fn new(condition: impl FnOnce() -> bool, iter: I, chunk_size: usize, chunks_in_flight: usize) -> Self {
+ if condition() {
+ EagerIterIf::Eager(EagerIter::new(iter, chunk_size, chunks_in_flight))
+ } else {
+ EagerIterIf::OnDemand(iter)
+ }
+ }
+}
+impl<I> Iterator for EagerIterIf<I>
+where
+ I: Iterator + Send + 'static,
+ <I as Iterator>::Item: Send,
+{
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self {
+ EagerIterIf::OnDemand(i) => i.next(),
+ EagerIterIf::Eager(i) => i.next(),
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ match self {
+ EagerIterIf::OnDemand(i) => i.size_hint(),
+ EagerIterIf::Eager(i) => i.size_hint(),
+ }
+ }
+}
diff --git a/vendor/gix-features/src/parallel/in_order.rs b/vendor/gix-features/src/parallel/in_order.rs
new file mode 100644
index 000000000..7928ac692
--- /dev/null
+++ b/vendor/gix-features/src/parallel/in_order.rs
@@ -0,0 +1,83 @@
+use std::{cmp::Ordering, collections::BTreeMap};
+
+/// A counter for items that are in sequence, to be able to put them back into original order later.
+pub type SequenceId = usize;
+
+/// An iterator which olds iterated items with a **sequential** ID starting at 0 long enough to dispense them in order.
+pub struct InOrderIter<T, I> {
+ /// The iterator yielding the out-of-order elements we are to yield in order.
+ pub inner: I,
+ store: BTreeMap<SequenceId, T>,
+ next_chunk: SequenceId,
+ is_done: bool,
+}
+
+impl<T, E, I> From<I> for InOrderIter<T, I>
+where
+ I: Iterator<Item = Result<(SequenceId, T), E>>,
+{
+ fn from(iter: I) -> Self {
+ InOrderIter {
+ inner: iter,
+ store: Default::default(),
+ next_chunk: 0,
+ is_done: false,
+ }
+ }
+}
+
+impl<T, E, I> Iterator for InOrderIter<T, I>
+where
+ I: Iterator<Item = Result<(SequenceId, T), E>>,
+{
+ type Item = Result<T, E>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.is_done {
+ return None;
+ }
+ 'find_next_in_sequence: loop {
+ match self.inner.next() {
+ Some(Ok((c, v))) => match c.cmp(&self.next_chunk) {
+ Ordering::Equal => {
+ self.next_chunk += 1;
+ return Some(Ok(v));
+ }
+ Ordering::Less => {
+ unreachable!("in a correctly ordered sequence we can never see keys again, got {}", c)
+ }
+ Ordering::Greater => {
+ let previous = self.store.insert(c, v);
+ assert!(
+ previous.is_none(),
+ "Chunks are returned only once, input is an invalid sequence"
+ );
+ if let Some(v) = self.store.remove(&self.next_chunk) {
+ self.next_chunk += 1;
+ return Some(Ok(v));
+ }
+ continue 'find_next_in_sequence;
+ }
+ },
+ Some(Err(e)) => {
+ self.is_done = true;
+ self.store.clear();
+ return Some(Err(e));
+ }
+ None => match self.store.remove(&self.next_chunk) {
+ Some(v) => {
+ self.next_chunk += 1;
+ return Some(Ok(v));
+ }
+ None => {
+ debug_assert!(
+ self.store.is_empty(),
+ "When iteration is done we should not have stored items left"
+ );
+ return None;
+ }
+ },
+ }
+ }
+ }
+}
diff --git a/vendor/gix-features/src/parallel/in_parallel.rs b/vendor/gix-features/src/parallel/in_parallel.rs
new file mode 100644
index 000000000..e1e2cc3e3
--- /dev/null
+++ b/vendor/gix-features/src/parallel/in_parallel.rs
@@ -0,0 +1,211 @@
+use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+
+use crate::parallel::{num_threads, Reduce};
+
+/// Runs `left` and `right` in parallel, returning their output when both are done.
+pub fn join<O1: Send, O2: Send>(left: impl FnOnce() -> O1 + Send, right: impl FnOnce() -> O2 + Send) -> (O1, O2) {
+ std::thread::scope(|s| {
+ let left = std::thread::Builder::new()
+ .name("gitoxide.join.left".into())
+ .spawn_scoped(s, left)
+ .expect("valid name");
+ let right = std::thread::Builder::new()
+ .name("gitoxide.join.right".into())
+ .spawn_scoped(s, right)
+ .expect("valid name");
+ (left.join().unwrap(), right.join().unwrap())
+ })
+}
+
+/// Runs `f` with a scope to be used for spawning threads that will not outlive the function call.
+/// That way it's possible to handle threads without needing the 'static lifetime for data they interact with.
+///
+/// Note that the threads should not rely on actual parallelism as threading might be turned off entirely, hence should not
+/// connect each other with channels as deadlock would occur in single-threaded mode.
+pub fn threads<'env, F, R>(f: F) -> R
+where
+ F: for<'scope> FnOnce(&'scope std::thread::Scope<'scope, 'env>) -> R,
+{
+ std::thread::scope(f)
+}
+
+/// Create a builder for threads which allows them to be spawned into a scope and configured prior to spawning.
+pub fn build_thread() -> std::thread::Builder {
+ std::thread::Builder::new()
+}
+
+/// Read items from `input` and `consume` them in multiple threads,
+/// whose output output is collected by a `reducer`. Its task is to
+/// aggregate these outputs into the final result returned by this function with the benefit of not having to be thread-safe.
+///
+/// * if `thread_limit` is `Some`, the given amount of threads will be used. If `None`, all logical cores will be used.
+/// * `new_thread_state(thread_number) -> State` produces thread-local state once per thread to be based to `consume`
+/// * `consume(Item, &mut State) -> Output` produces an output given an input obtained by `input` along with mutable state initially
+/// created by `new_thread_state(…)`.
+/// * For `reducer`, see the [`Reduce`] trait
+pub fn in_parallel<I, S, O, R>(
+ input: impl Iterator<Item = I> + Send,
+ thread_limit: Option<usize>,
+ new_thread_state: impl Fn(usize) -> S + Send + Clone,
+ consume: impl Fn(I, &mut S) -> O + Send + Clone,
+ mut reducer: R,
+) -> Result<<R as Reduce>::Output, <R as Reduce>::Error>
+where
+ R: Reduce<Input = O>,
+ I: Send,
+ O: Send,
+{
+ let num_threads = num_threads(thread_limit);
+ std::thread::scope(move |s| {
+ let receive_result = {
+ let (send_input, receive_input) = crossbeam_channel::bounded::<I>(num_threads);
+ let (send_result, receive_result) = crossbeam_channel::bounded::<O>(num_threads);
+ for thread_id in 0..num_threads {
+ std::thread::Builder::new()
+ .name(format!("gitoxide.in_parallel.produce.{thread_id}"))
+ .spawn_scoped(s, {
+ let send_result = send_result.clone();
+ let receive_input = receive_input.clone();
+ let new_thread_state = new_thread_state.clone();
+ let consume = consume.clone();
+ move || {
+ let mut state = new_thread_state(thread_id);
+ for item in receive_input {
+ if send_result.send(consume(item, &mut state)).is_err() {
+ break;
+ }
+ }
+ }
+ })
+ .expect("valid name");
+ }
+ std::thread::Builder::new()
+ .name("gitoxide.in_parallel.feed".into())
+ .spawn_scoped(s, move || {
+ for item in input {
+ if send_input.send(item).is_err() {
+ break;
+ }
+ }
+ })
+ .expect("valid name");
+ receive_result
+ };
+
+ for item in receive_result {
+ drop(reducer.feed(item)?);
+ }
+ reducer.finalize()
+ })
+}
+
+/// An experiment to have fine-grained per-item parallelization with built-in aggregation via thread state.
+/// This is only good for operations where near-random access isn't detrimental, so it's not usually great
+/// for file-io as it won't make use of sorted inputs well.
+/// Note that `periodic` is not guaranteed to be called in case other threads come up first and finish too fast.
+// TODO: better docs
+pub fn in_parallel_with_slice<I, S, R, E>(
+ input: &mut [I],
+ thread_limit: Option<usize>,
+ new_thread_state: impl FnMut(usize) -> S + Send + Clone,
+ consume: impl FnMut(&mut I, &mut S) -> Result<(), E> + Send + Clone,
+ mut periodic: impl FnMut() -> Option<std::time::Duration> + Send,
+ state_to_rval: impl FnOnce(S) -> R + Send + Clone,
+) -> Result<Vec<R>, E>
+where
+ I: Send,
+ E: Send,
+ R: Send,
+{
+ let num_threads = num_threads(thread_limit);
+ let mut results = Vec::with_capacity(num_threads);
+ let stop_everything = &AtomicBool::default();
+ let index = &AtomicUsize::default();
+
+ // TODO: use std::thread::scope() once Rust 1.63 is available.
+ std::thread::scope({
+ move |s| {
+ std::thread::Builder::new()
+ .name("gitoxide.in_parallel_with_slice.watch-interrupts".into())
+ .spawn_scoped(s, {
+ move || loop {
+ if stop_everything.load(Ordering::Relaxed) {
+ break;
+ }
+
+ match periodic() {
+ Some(duration) => std::thread::sleep(duration),
+ None => {
+ stop_everything.store(true, Ordering::Relaxed);
+ break;
+ }
+ }
+ }
+ })
+ .expect("valid name");
+
+ let input_len = input.len();
+ struct Input<I>(*mut [I])
+ where
+ I: Send;
+
+ // SAFETY: I is Send + Sync, so is a *mut [I]
+ #[allow(unsafe_code)]
+ unsafe impl<I> Send for Input<I> where I: Send {}
+
+ let threads: Vec<_> = (0..num_threads)
+ .map(|thread_id| {
+ std::thread::Builder::new()
+ .name(format!("gitoxide.in_parallel_with_slice.produce.{thread_id}"))
+ .spawn_scoped(s, {
+ let mut new_thread_state = new_thread_state.clone();
+ let state_to_rval = state_to_rval.clone();
+ let mut consume = consume.clone();
+ let input = Input(input as *mut [I]);
+ move || {
+ let mut state = new_thread_state(thread_id);
+ while let Ok(input_index) =
+ index.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
+ (x < input_len).then_some(x + 1)
+ })
+ {
+ if stop_everything.load(Ordering::Relaxed) {
+ break;
+ }
+ // SAFETY: our atomic counter for `input_index` is only ever incremented, yielding
+ // each item exactly once.
+ let item = {
+ #[allow(unsafe_code)]
+ unsafe {
+ &mut (&mut *input.0)[input_index]
+ }
+ };
+ if let Err(err) = consume(item, &mut state) {
+ stop_everything.store(true, Ordering::Relaxed);
+ return Err(err);
+ }
+ }
+ Ok(state_to_rval(state))
+ }
+ })
+ .expect("valid name")
+ })
+ .collect();
+ for thread in threads {
+ match thread.join() {
+ Ok(res) => {
+ results.push(res?);
+ }
+ Err(err) => {
+ // a panic happened, stop the world gracefully (even though we panic later)
+ stop_everything.store(true, Ordering::Relaxed);
+ std::panic::resume_unwind(err);
+ }
+ }
+ }
+
+ stop_everything.store(true, Ordering::Relaxed);
+ Ok(results)
+ }
+ })
+}
diff --git a/vendor/gix-features/src/parallel/mod.rs b/vendor/gix-features/src/parallel/mod.rs
new file mode 100644
index 000000000..c994cb3b8
--- /dev/null
+++ b/vendor/gix-features/src/parallel/mod.rs
@@ -0,0 +1,179 @@
+//! Run computations in parallel, or not based the `parallel` feature toggle.
+//!
+//! ### in_parallel(…)
+//!
+//! The [`in_parallel(…)`][in_parallel()] is the typical fan-out-fan-in mode of parallelism, with thread local storage
+//! made available to a `consume(…)` function to process input. The result is sent to the [`Reduce`] running in the calling
+//! thread to aggregate the results into a single output, which is returned by [`in_parallel()`].
+//!
+//! Interruptions can be achieved by letting the reducers [`feed(…)`][Reduce::feed()]` method fail.
+//!
+//! It gets a boost in usability as it allows threads to borrow variables from the stack, most commonly the repository itself
+//! or the data to work on.
+//!
+//! This mode of operation doesn't lend itself perfectly to being wrapped for `async` as it appears like a single long-running
+//! operation which runs as fast as possible, which is cancellable only by merit of stopping the input or stopping the output
+//! aggregation.
+//!
+//! ### `reduce::Stepwise`
+//!
+//! The [`Stepwise`][reduce::Stepwise] iterator works exactly as [`in_parallel()`] except that the processing of the output produced by
+//! `consume(I, &mut State) -> O` is made accessible by the `Iterator` trait's `next()` method. As produced work is not
+//! buffered, the owner of the iterator controls the progress made.
+//!
+//! Getting the final output of the [`Reduce`] is achieved through the consuming [`Stepwise::finalize()`][reduce::Stepwise::finalize()] method, which
+//! is functionally equivalent to calling [`in_parallel()`].
+//!
+//! In an `async` context this means that progress is only made each time `next()` is called on the iterator, while merely dropping
+//! the iterator will wind down the computation without any result.
+//!
+//! #### Maintaining Safety
+//!
+//! In order to assure that threads don't outlive the data they borrow because their handles are leaked, we enforce
+//! the `'static` lifetime for its inputs, making it less intuitive to use. It is, however, possible to produce
+//! suitable input iterators as long as they can hold something on the heap.
+#[cfg(feature = "parallel")]
+mod in_parallel;
+#[cfg(feature = "parallel")]
+pub use in_parallel::{build_thread, in_parallel, in_parallel_with_slice, join, threads};
+
+mod serial;
+#[cfg(not(feature = "parallel"))]
+pub use serial::{build_thread, in_parallel, in_parallel_with_slice, join, threads};
+
+mod in_order;
+pub use in_order::{InOrderIter, SequenceId};
+
+mod eager_iter;
+pub use eager_iter::{EagerIter, EagerIterIf};
+
+/// A no-op returning the input _(`desired_chunk_size`, `Some(thread_limit)`, `thread_limit)_ used
+/// when the `parallel` feature toggle is not set.
+#[cfg(not(feature = "parallel"))]
+pub fn optimize_chunk_size_and_thread_limit(
+ desired_chunk_size: usize,
+ _num_items: Option<usize>,
+ thread_limit: Option<usize>,
+ _available_threads: Option<usize>,
+) -> (usize, Option<usize>, usize) {
+ (desired_chunk_size, thread_limit, num_threads(thread_limit))
+}
+
+/// Return the 'optimal' _(`size of chunks`, `amount of threads as Option`, `amount of threads`)_ to use in [`in_parallel()`] for the given
+/// `desired_chunk_size`, `num_items`, `thread_limit` and `available_threads`.
+///
+/// * `desired_chunk_size` is the amount of items per chunk you think should be used.
+/// * `num_items` is the total amount of items in the iteration, if `Some`.
+/// Otherwise this knowledge will not affect the output of this function.
+/// * `thread_limit` is the amount of threads to use at most, if `Some`.
+/// Otherwise this knowledge will not affect the output of this function.
+/// * `available_threads` is the total amount of threads available, if `Some`.
+/// Otherwise the actual amount of available threads is determined by querying the system.
+///
+/// `Note` that this implementation is available only if the `parallel` feature toggle is set.
+#[cfg(feature = "parallel")]
+pub fn optimize_chunk_size_and_thread_limit(
+ desired_chunk_size: usize,
+ num_items: Option<usize>,
+ thread_limit: Option<usize>,
+ available_threads: Option<usize>,
+) -> (usize, Option<usize>, usize) {
+ let available_threads =
+ available_threads.unwrap_or_else(|| std::thread::available_parallelism().map(|n| n.get()).unwrap_or(1));
+ let available_threads = thread_limit
+ .map(|l| if l == 0 { available_threads } else { l })
+ .unwrap_or(available_threads);
+
+ let (lower, upper) = (50, 1000);
+ let (chunk_size, thread_limit) = num_items
+ .map(|num_items| {
+ let desired_chunks_per_thread_at_least = 2;
+ let items = num_items;
+ let chunk_size = (items / (available_threads * desired_chunks_per_thread_at_least)).clamp(1, upper);
+ let num_chunks = items / chunk_size;
+ let thread_limit = if num_chunks <= available_threads {
+ (num_chunks / desired_chunks_per_thread_at_least).max(1)
+ } else {
+ available_threads
+ };
+ (chunk_size, thread_limit)
+ })
+ .unwrap_or({
+ let chunk_size = if available_threads == 1 {
+ desired_chunk_size
+ } else if desired_chunk_size < lower {
+ lower
+ } else {
+ desired_chunk_size.min(upper)
+ };
+ (chunk_size, available_threads)
+ });
+ (chunk_size, Some(thread_limit), thread_limit)
+}
+
+/// Always returns 1, available when the `parallel` feature toggle is unset.
+#[cfg(not(feature = "parallel"))]
+pub fn num_threads(_thread_limit: Option<usize>) -> usize {
+ 1
+}
+
+/// Returns the amount of threads the system can effectively use as the amount of its logical cores.
+///
+/// Only available with the `parallel` feature toggle set.
+#[cfg(feature = "parallel")]
+pub fn num_threads(thread_limit: Option<usize>) -> usize {
+ let logical_cores = std::thread::available_parallelism().map(|n| n.get()).unwrap_or(1);
+ thread_limit
+ .map(|l| if l == 0 { logical_cores } else { l })
+ .unwrap_or(logical_cores)
+}
+
+/// Run [`in_parallel()`] only if the given `condition()` returns true when eagerly evaluated.
+///
+/// For parameters, see the documentation of [`in_parallel()`]
+#[cfg(feature = "parallel")]
+pub fn in_parallel_if<I, S, O, R>(
+ condition: impl FnOnce() -> bool,
+ input: impl Iterator<Item = I> + Send,
+ thread_limit: Option<usize>,
+ new_thread_state: impl Fn(usize) -> S + Send + Clone,
+ consume: impl Fn(I, &mut S) -> O + Send + Clone,
+ reducer: R,
+) -> Result<<R as Reduce>::Output, <R as Reduce>::Error>
+where
+ R: Reduce<Input = O>,
+ I: Send,
+ O: Send,
+{
+ if num_threads(thread_limit) > 1 && condition() {
+ in_parallel(input, thread_limit, new_thread_state, consume, reducer)
+ } else {
+ serial::in_parallel(input, thread_limit, new_thread_state, consume, reducer)
+ }
+}
+
+/// Run [`in_parallel()`] only if the given `condition()` returns true when eagerly evaluated.
+///
+/// For parameters, see the documentation of [`in_parallel()`]
+///
+/// Note that the non-parallel version is equivalent to [`in_parallel()`].
+#[cfg(not(feature = "parallel"))]
+pub fn in_parallel_if<I, S, O, R>(
+ _condition: impl FnOnce() -> bool,
+ input: impl Iterator<Item = I>,
+ thread_limit: Option<usize>,
+ new_thread_state: impl Fn(usize) -> S,
+ consume: impl Fn(I, &mut S) -> O,
+ reducer: R,
+) -> Result<<R as Reduce>::Output, <R as Reduce>::Error>
+where
+ R: Reduce<Input = O>,
+ I: Send,
+ O: Send,
+{
+ serial::in_parallel(input, thread_limit, new_thread_state, consume, reducer)
+}
+
+///
+pub mod reduce;
+pub use reduce::Reduce;
diff --git a/vendor/gix-features/src/parallel/reduce.rs b/vendor/gix-features/src/parallel/reduce.rs
new file mode 100644
index 000000000..f9992cfd2
--- /dev/null
+++ b/vendor/gix-features/src/parallel/reduce.rs
@@ -0,0 +1,279 @@
+#[cfg(feature = "parallel")]
+mod stepped {
+ use crate::parallel::num_threads;
+
+ /// An iterator adaptor to allow running computations using [`in_parallel()`][crate::parallel::in_parallel()] in a step-wise manner, see the [module docs][crate::parallel]
+ /// for details.
+ pub struct Stepwise<Reduce: super::Reduce> {
+ /// This field is first to assure it's dropped first and cause threads that are dropped next to stop their loops
+ /// as sending results fails when the receiver is dropped.
+ receive_result: std::sync::mpsc::Receiver<Reduce::Input>,
+ /// `join()` will be called on these guards to assure every thread tries to send through a closed channel. When
+ /// that happens, they break out of their loops.
+ threads: Vec<std::thread::JoinHandle<()>>,
+ /// The reducer is called only in the thread using the iterator, dropping it has no side effects.
+ reducer: Option<Reduce>,
+ }
+
+ impl<Reduce: super::Reduce> Drop for Stepwise<Reduce> {
+ fn drop(&mut self) {
+ let (_, sink) = std::sync::mpsc::channel();
+ drop(std::mem::replace(&mut self.receive_result, sink));
+
+ let mut last_err = None;
+ for handle in std::mem::take(&mut self.threads) {
+ if let Err(err) = handle.join() {
+ last_err = Some(err);
+ };
+ }
+ if let Some(thread_err) = last_err {
+ std::panic::resume_unwind(thread_err);
+ }
+ }
+ }
+
+ impl<Reduce: super::Reduce> Stepwise<Reduce> {
+ /// Instantiate a new iterator and start working in threads.
+ /// For a description of parameters, see [`in_parallel()`][crate::parallel::in_parallel()].
+ pub fn new<InputIter, ThreadStateFn, ConsumeFn, I, O, S>(
+ input: InputIter,
+ thread_limit: Option<usize>,
+ new_thread_state: ThreadStateFn,
+ consume: ConsumeFn,
+ reducer: Reduce,
+ ) -> Self
+ where
+ InputIter: Iterator<Item = I> + Send + 'static,
+ ThreadStateFn: Fn(usize) -> S + Send + Clone + 'static,
+ ConsumeFn: Fn(I, &mut S) -> O + Send + Clone + 'static,
+ Reduce: super::Reduce<Input = O> + 'static,
+ I: Send + 'static,
+ O: Send + 'static,
+ {
+ let num_threads = num_threads(thread_limit);
+ let mut threads = Vec::with_capacity(num_threads + 1);
+ let receive_result = {
+ let (send_input, receive_input) = crossbeam_channel::bounded::<I>(num_threads);
+ let (send_result, receive_result) = std::sync::mpsc::sync_channel::<O>(num_threads);
+ for thread_id in 0..num_threads {
+ let handle = std::thread::spawn({
+ let send_result = send_result.clone();
+ let receive_input = receive_input.clone();
+ let new_thread_state = new_thread_state.clone();
+ let consume = consume.clone();
+ move || {
+ let mut state = new_thread_state(thread_id);
+ for item in receive_input {
+ if send_result.send(consume(item, &mut state)).is_err() {
+ break;
+ }
+ }
+ }
+ });
+ threads.push(handle);
+ }
+ threads.push(std::thread::spawn(move || {
+ for item in input {
+ if send_input.send(item).is_err() {
+ break;
+ }
+ }
+ }));
+ receive_result
+ };
+ Stepwise {
+ threads,
+ receive_result,
+ reducer: Some(reducer),
+ }
+ }
+
+ /// Consume the iterator by finishing its iteration and calling [`Reduce::finalize()`][crate::parallel::Reduce::finalize()].
+ pub fn finalize(mut self) -> Result<Reduce::Output, Reduce::Error> {
+ for value in self.by_ref() {
+ drop(value?);
+ }
+ self.reducer
+ .take()
+ .expect("this is the last call before consumption")
+ .finalize()
+ }
+ }
+
+ impl<Reduce: super::Reduce> Iterator for Stepwise<Reduce> {
+ type Item = Result<Reduce::FeedProduce, Reduce::Error>;
+
+ fn next(&mut self) -> Option<<Self as Iterator>::Item> {
+ self.receive_result
+ .recv()
+ .ok()
+ .and_then(|input| self.reducer.as_mut().map(|r| r.feed(input)))
+ }
+ }
+
+ impl<R: super::Reduce> super::Finalize for Stepwise<R> {
+ type Reduce = R;
+
+ fn finalize(
+ self,
+ ) -> Result<
+ <<Self as super::Finalize>::Reduce as super::Reduce>::Output,
+ <<Self as super::Finalize>::Reduce as super::Reduce>::Error,
+ > {
+ Stepwise::finalize(self)
+ }
+ }
+}
+
+#[cfg(not(feature = "parallel"))]
+mod stepped {
+ /// An iterator adaptor to allow running computations using [`in_parallel()`][crate::parallel::in_parallel()] in a step-wise manner, see the [module docs][crate::parallel]
+ /// for details.
+ pub struct Stepwise<InputIter, ConsumeFn, ThreadState, Reduce> {
+ input: InputIter,
+ consume: ConsumeFn,
+ thread_state: ThreadState,
+ reducer: Reduce,
+ }
+
+ impl<InputIter, ConsumeFn, Reduce, I, O, S> Stepwise<InputIter, ConsumeFn, S, Reduce>
+ where
+ InputIter: Iterator<Item = I>,
+ ConsumeFn: Fn(I, &mut S) -> O,
+ Reduce: super::Reduce<Input = O>,
+ {
+ /// Instantiate a new iterator.
+ /// For a description of parameters, see [`in_parallel()`][crate::parallel::in_parallel()].
+ pub fn new<ThreadStateFn>(
+ input: InputIter,
+ _thread_limit: Option<usize>,
+ new_thread_state: ThreadStateFn,
+ consume: ConsumeFn,
+ reducer: Reduce,
+ ) -> Self
+ where
+ ThreadStateFn: Fn(usize) -> S,
+ {
+ Stepwise {
+ input,
+ consume,
+ thread_state: new_thread_state(0),
+ reducer,
+ }
+ }
+
+ /// Consume the iterator by finishing its iteration and calling [`Reduce::finalize()`][crate::parallel::Reduce::finalize()].
+ pub fn finalize(mut self) -> Result<Reduce::Output, Reduce::Error> {
+ for value in self.by_ref() {
+ drop(value?);
+ }
+ self.reducer.finalize()
+ }
+ }
+
+ impl<InputIter, ConsumeFn, ThreadState, Reduce, I, O> Iterator for Stepwise<InputIter, ConsumeFn, ThreadState, Reduce>
+ where
+ InputIter: Iterator<Item = I>,
+ ConsumeFn: Fn(I, &mut ThreadState) -> O,
+ Reduce: super::Reduce<Input = O>,
+ {
+ type Item = Result<Reduce::FeedProduce, Reduce::Error>;
+
+ fn next(&mut self) -> Option<<Self as Iterator>::Item> {
+ self.input
+ .next()
+ .map(|input| self.reducer.feed((self.consume)(input, &mut self.thread_state)))
+ }
+ }
+
+ impl<InputIter, ConsumeFn, R, I, O, S> super::Finalize for Stepwise<InputIter, ConsumeFn, S, R>
+ where
+ InputIter: Iterator<Item = I>,
+ ConsumeFn: Fn(I, &mut S) -> O,
+ R: super::Reduce<Input = O>,
+ {
+ type Reduce = R;
+
+ fn finalize(
+ self,
+ ) -> Result<
+ <<Self as super::Finalize>::Reduce as super::Reduce>::Output,
+ <<Self as super::Finalize>::Reduce as super::Reduce>::Error,
+ > {
+ Stepwise::finalize(self)
+ }
+ }
+}
+
+use std::marker::PhantomData;
+
+pub use stepped::Stepwise;
+
+/// An trait for aggregating items commonly produced in threads into a single result, without itself
+/// needing to be thread safe.
+pub trait Reduce {
+ /// The type fed to the reducer in the [`feed()`][Reduce::feed()] method.
+ ///
+ /// It's produced by a function that may run on multiple threads.
+ type Input;
+ /// The type produced in Ok(…) by [`feed()`][Reduce::feed()].
+ /// Most reducers by nature use `()` here as the value is in the aggregation.
+ /// However, some may use it to collect statistics only and return their Input
+ /// in some form as a result here for [`Stepwise`] to be useful.
+ type FeedProduce;
+ /// The type produced once by the [`finalize()`][Reduce::finalize()] method.
+ ///
+ /// For traditional reducers, this is the value produced by the entire operation.
+ /// For those made for step-wise iteration this may be aggregated statistics.
+ type Output;
+ /// The error type to use for all methods of this trait.
+ type Error;
+ /// Called each time a new `item` was produced in order to aggregate it into the final result.
+ ///
+ /// If an `Error` is returned, the entire operation will be stopped.
+ fn feed(&mut self, item: Self::Input) -> Result<Self::FeedProduce, Self::Error>;
+ /// Called once once all items where passed to `feed()`, producing the final `Output` of the operation or an `Error`.
+ fn finalize(self) -> Result<Self::Output, Self::Error>;
+}
+
+/// An identity reducer for those who want to use [`Stepwise`] or [`in_parallel()`][crate::parallel::in_parallel()]
+/// without the use of non-threaded reduction of products created in threads.
+pub struct IdentityWithResult<Input, Error> {
+ _input: PhantomData<Input>,
+ _error: PhantomData<Error>,
+}
+
+impl<Input, Error> Default for IdentityWithResult<Input, Error> {
+ fn default() -> Self {
+ IdentityWithResult {
+ _input: Default::default(),
+ _error: Default::default(),
+ }
+ }
+}
+
+impl<Input, Error> Reduce for IdentityWithResult<Input, Error> {
+ type Input = Result<Input, Self::Error>;
+ type FeedProduce = Input;
+ type Output = ();
+ type Error = Error;
+
+ fn feed(&mut self, item: Self::Input) -> Result<Self::FeedProduce, Self::Error> {
+ item
+ }
+
+ fn finalize(self) -> Result<Self::Output, Self::Error> {
+ Ok(())
+ }
+}
+
+/// A trait reflecting the `finalize()` method of [`Reduce`] implementations
+pub trait Finalize {
+ /// An implementation of [`Reduce`]
+ type Reduce: self::Reduce;
+
+ /// Similar to the [`Reduce::finalize()`] method
+ fn finalize(
+ self,
+ ) -> Result<<<Self as Finalize>::Reduce as self::Reduce>::Output, <<Self as Finalize>::Reduce as self::Reduce>::Error>;
+}
diff --git a/vendor/gix-features/src/parallel/serial.rs b/vendor/gix-features/src/parallel/serial.rs
new file mode 100644
index 000000000..00723b2c3
--- /dev/null
+++ b/vendor/gix-features/src/parallel/serial.rs
@@ -0,0 +1,135 @@
+use crate::parallel::Reduce;
+
+#[cfg(not(feature = "parallel"))]
+mod not_parallel {
+ /// Runs `left` and then `right`, one after another, returning their output when both are done.
+ pub fn join<O1, O2>(left: impl FnOnce() -> O1, right: impl FnOnce() -> O2) -> (O1, O2) {
+ (left(), right())
+ }
+
+ /// A scope for spawning threads.
+ pub struct Scope<'env> {
+ _marker: std::marker::PhantomData<&'env mut &'env ()>,
+ }
+
+ pub struct ThreadBuilder;
+
+ /// Create a builder for threads which allows them to be spawned into a scope and configured prior to spawning.
+ pub fn build_thread() -> ThreadBuilder {
+ ThreadBuilder
+ }
+
+ #[allow(unsafe_code)]
+ unsafe impl Sync for Scope<'_> {}
+
+ impl ThreadBuilder {
+ pub fn name(self, _new: String) -> Self {
+ self
+ }
+ pub fn spawn_scoped<'a, 'env, F, T>(
+ &self,
+ scope: &'a Scope<'env>,
+ f: F,
+ ) -> std::io::Result<ScopedJoinHandle<'a, T>>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'env,
+ T: Send + 'env,
+ {
+ Ok(scope.spawn(f))
+ }
+ }
+
+ impl<'env> Scope<'env> {
+ pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'env,
+ T: Send + 'env,
+ {
+ ScopedJoinHandle {
+ result: f(),
+ _marker: Default::default(),
+ }
+ }
+ }
+
+ /// Runs `f` with a scope to be used for spawning threads that will not outlive the function call.
+ /// Note that this implementation will run the spawned functions immediately.
+ pub fn threads<'env, F, R>(f: F) -> R
+ where
+ F: FnOnce(&Scope<'env>) -> R,
+ {
+ f(&Scope {
+ _marker: Default::default(),
+ })
+ }
+
+ /// A handle that can be used to join its scoped thread.
+ ///
+ /// This struct is created by the [`Scope::spawn`] method and the
+ /// [`ScopedThreadBuilder::spawn`] method.
+ pub struct ScopedJoinHandle<'scope, T> {
+ /// Holds the result of the inner closure.
+ result: T,
+ _marker: std::marker::PhantomData<&'scope mut &'scope ()>,
+ }
+
+ impl<T> ScopedJoinHandle<'_, T> {
+ pub fn join(self) -> std::thread::Result<T> {
+ Ok(self.result)
+ }
+ }
+
+ /// An experiment to have fine-grained per-item parallelization with built-in aggregation via thread state.
+ /// This is only good for operations where near-random access isn't detrimental, so it's not usually great
+ /// for file-io as it won't make use of sorted inputs well.
+ // TODO: better docs
+ pub fn in_parallel_with_slice<I, S, R, E>(
+ input: &mut [I],
+ _thread_limit: Option<usize>,
+ mut new_thread_state: impl FnMut(usize) -> S + Clone,
+ mut consume: impl FnMut(&mut I, &mut S) -> Result<(), E> + Clone,
+ mut periodic: impl FnMut() -> Option<std::time::Duration>,
+ state_to_rval: impl FnOnce(S) -> R + Clone,
+ ) -> Result<Vec<R>, E> {
+ let mut state = new_thread_state(0);
+ for item in input {
+ consume(item, &mut state)?;
+ if periodic().is_none() {
+ break;
+ }
+ }
+ Ok(vec![state_to_rval(state)])
+ }
+}
+
+#[cfg(not(feature = "parallel"))]
+pub use not_parallel::{build_thread, in_parallel_with_slice, join, threads, Scope, ScopedJoinHandle};
+
+/// Read items from `input` and `consume` them in a single thread, producing an output to be collected by a `reducer`,
+/// whose task is to aggregate these outputs into the final result returned by this function.
+///
+/// * `new_thread_state(thread_number) -> State` produces thread-local state once per thread to be based to `consume`
+/// * `consume(Item, &mut State) -> Output` produces an output given an input along with mutable state.
+/// * For `reducer`, see the [`Reduce`] trait
+/// * if `thread_limit` has no effect as everything is run on the main thread, but is present to keep the signature
+/// similar to the parallel version.
+///
+/// **This serial version performing all calculations on the current thread.**
+pub fn in_parallel<I, S, O, R>(
+ input: impl Iterator<Item = I>,
+ _thread_limit: Option<usize>,
+ new_thread_state: impl Fn(usize) -> S,
+ consume: impl Fn(I, &mut S) -> O,
+ mut reducer: R,
+) -> Result<<R as Reduce>::Output, <R as Reduce>::Error>
+where
+ R: Reduce<Input = O>,
+{
+ let mut state = new_thread_state(0);
+ for item in input {
+ drop(reducer.feed(consume(item, &mut state))?);
+ }
+ reducer.finalize()
+}
diff --git a/vendor/gix-features/src/progress.rs b/vendor/gix-features/src/progress.rs
new file mode 100644
index 000000000..b6e56895b
--- /dev/null
+++ b/vendor/gix-features/src/progress.rs
@@ -0,0 +1,139 @@
+//! Various `prodash` types along with various utilities for comfort.
+use std::io;
+
+pub use prodash::{
+ self,
+ messages::MessageLevel,
+ progress::{Discard, DoOrDiscard, Either, Id, Step, StepShared, Task, ThroughputOnDrop, Value, UNKNOWN},
+ unit, Progress, Unit,
+};
+
+#[cfg(feature = "progress-unit-bytes")]
+pub use bytesize;
+/// A stub for the portions of the `bytesize` crate that we use internally in `gitoxide`.
+#[cfg(not(feature = "progress-unit-bytes"))]
+pub mod bytesize {
+ /// A stub for the `ByteSize` wrapper.
+ pub struct ByteSize(pub u64);
+
+ impl std::fmt::Display for ByteSize {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+ }
+}
+
+/// A unit for displaying bytes with throughput and progress percentage.
+#[cfg(feature = "progress-unit-bytes")]
+pub fn bytes() -> Option<Unit> {
+ Some(unit::dynamic_and_mode(
+ unit::Bytes,
+ unit::display::Mode::with_throughput().and_percentage(),
+ ))
+}
+
+/// A unit for displaying bytes with throughput and progress percentage.
+#[cfg(not(feature = "progress-unit-bytes"))]
+pub fn bytes() -> Option<Unit> {
+ Some(unit::label_and_mode(
+ "B",
+ unit::display::Mode::with_throughput().and_percentage(),
+ ))
+}
+
+/// A unit for displaying human readable numbers with throughput and progress percentage, and a single decimal place.
+pub fn count(name: &'static str) -> Option<Unit> {
+ count_with_decimals(name, 1)
+}
+
+/// A unit for displaying human readable numbers with `name` suffix,
+/// with throughput and progress percentage, and `decimals` decimal places.
+#[cfg(feature = "progress-unit-human-numbers")]
+pub fn count_with_decimals(name: &'static str, decimals: usize) -> Option<Unit> {
+ Some(unit::dynamic_and_mode(
+ unit::Human::new(
+ {
+ let mut f = unit::human::Formatter::new();
+ f.with_decimals(decimals);
+ f
+ },
+ name,
+ ),
+ unit::display::Mode::with_throughput().and_percentage(),
+ ))
+}
+
+/// A unit for displaying human readable numbers with `name` suffix,
+/// with throughput and progress percentage, and `decimals` decimal places.
+#[cfg(not(feature = "progress-unit-human-numbers"))]
+pub fn count_with_decimals(name: &'static str, _decimals: usize) -> Option<Unit> {
+ Some(unit::label_and_mode(
+ name,
+ unit::display::Mode::with_throughput().and_percentage(),
+ ))
+}
+
+/// A predefined unit for displaying a multi-step progress
+pub fn steps() -> Option<Unit> {
+ Some(unit::dynamic(unit::Range::new("steps")))
+}
+
+/// A structure passing every [`read`][std::io::Read::read()] call through to the contained Progress instance using [`inc_by(bytes_read)`][Progress::inc_by()].
+pub struct Read<T, P> {
+ /// The implementor of [`std::io::Read`] to which progress is added
+ pub inner: T,
+ /// The progress instance receiving progress information on each invocation of `reader`
+ pub progress: P,
+}
+
+impl<T, P> io::Read for Read<T, P>
+where
+ T: io::Read,
+ P: Progress,
+{
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let bytes_read = self.inner.read(buf)?;
+ self.progress.inc_by(bytes_read);
+ Ok(bytes_read)
+ }
+}
+
+impl<T, P> io::BufRead for Read<T, P>
+where
+ T: io::BufRead,
+ P: Progress,
+{
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ self.inner.fill_buf()
+ }
+
+ fn consume(&mut self, amt: usize) {
+ self.inner.consume(amt)
+ }
+}
+
+/// A structure passing every [`write`][std::io::Write::write()] call through to the contained Progress instance using [`inc_by(bytes_written)`][Progress::inc_by()].
+///
+/// This is particularly useful if the final size of the bytes to write is known or can be estimated precisely enough.
+pub struct Write<T, P> {
+ /// The implementor of [`std::io::Write`] to which progress is added
+ pub inner: T,
+ /// The progress instance receiving progress information on each invocation of `reader`
+ pub progress: P,
+}
+
+impl<T, P> io::Write for Write<T, P>
+where
+ T: io::Write,
+ P: Progress,
+{
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let written = self.inner.write(buf)?;
+ self.progress.inc_by(written);
+ Ok(written)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.flush()
+ }
+}
diff --git a/vendor/gix-features/src/threading.rs b/vendor/gix-features/src/threading.rs
new file mode 100644
index 000000000..ff0c819a5
--- /dev/null
+++ b/vendor/gix-features/src/threading.rs
@@ -0,0 +1,100 @@
+//! Type definitions for putting shared ownership and synchronized mutation behind the `threading` feature toggle.
+//!
+//! That way, single-threaded applications will not have to use thread-safe primitives, and simply do not specify the 'threading' feature.
+
+#[cfg(feature = "parallel")]
+mod _impl {
+ use std::sync::Arc;
+
+ /// A thread-safe cell which can be written to only once.
+ #[cfg(feature = "once_cell")]
+ pub type OnceCell<T> = once_cell::sync::OnceCell<T>;
+ /// A reference counted pointer type for shared ownership.
+ pub type OwnShared<T> = Arc<T>;
+ /// A synchronization primitive which can start read-only and transition to support mutation.
+ pub type MutableOnDemand<T> = parking_lot::RwLock<T>;
+ /// A synchronization primitive which provides read-write access right away.
+ pub type Mutable<T> = parking_lot::Mutex<T>;
+ /// A guarded reference suitable for safekeeping in a struct.
+ pub type RefGuard<'a, T> = parking_lot::RwLockReadGuard<'a, T>;
+ /// A mapped reference created from a RefGuard
+ pub type MappedRefGuard<'a, U> = parking_lot::MappedRwLockReadGuard<'a, U>;
+
+ /// Get a shared reference through a [`MutableOnDemand`] for read-only access.
+ pub fn get_ref<T>(v: &MutableOnDemand<T>) -> RefGuard<'_, T> {
+ v.read()
+ }
+
+ /// Get a mutable reference through a [`MutableOnDemand`] for read-write access.
+ pub fn get_mut<T>(v: &MutableOnDemand<T>) -> parking_lot::RwLockWriteGuard<'_, T> {
+ v.write()
+ }
+
+ /// Get a mutable reference through a [`Mutable`] for read-write access.
+ pub fn lock<T>(v: &Mutable<T>) -> parking_lot::MutexGuard<'_, T> {
+ v.lock()
+ }
+
+ /// Downgrade a handle previously obtained with [`get_mut()`] to drop mutation support.
+ pub fn downgrade_mut_to_ref<'a, T>(
+ v: parking_lot::RwLockWriteGuard<'a, T>,
+ _orig: &'a MutableOnDemand<T>,
+ ) -> RefGuard<'a, T> {
+ parking_lot::RwLockWriteGuard::downgrade(v)
+ }
+
+ /// Map a read guard into a sub-type it contains.
+ pub fn map_ref<T, U: ?Sized>(v: RefGuard<'_, T>, f: impl FnOnce(&T) -> &U) -> MappedRefGuard<'_, U> {
+ parking_lot::RwLockReadGuard::map(v, f)
+ }
+}
+
+#[cfg(not(feature = "parallel"))]
+mod _impl {
+ use std::{
+ cell::{Ref, RefCell, RefMut},
+ rc::Rc,
+ };
+
+ /// A thread-safe cell which can be written to only once.
+ #[cfg(feature = "once_cell")]
+ pub type OnceCell<T> = once_cell::unsync::OnceCell<T>;
+ /// A reference counted pointer type for shared ownership.
+ pub type OwnShared<T> = Rc<T>;
+ /// A synchronization primitive which can start read-only and transition to support mutation.
+ pub type MutableOnDemand<T> = RefCell<T>;
+ /// A synchronization primitive which provides read-write access right away.
+ pub type Mutable<T> = RefCell<T>;
+ /// A guarded reference suitable for safekeeping in a struct.
+ pub type RefGuard<'a, T> = Ref<'a, T>;
+ /// A mapped reference created from a RefGuard
+ pub type MappedRefGuard<'a, U> = Ref<'a, U>;
+
+ /// Get a shared reference through a [`MutableOnDemand`] for read-only access.
+ pub fn get_mut<T>(v: &RefCell<T>) -> RefMut<'_, T> {
+ v.borrow_mut()
+ }
+
+ /// Get a mutable reference through a [`Mutable`] for read-write access.
+ pub fn lock<T>(v: &Mutable<T>) -> RefMut<'_, T> {
+ v.borrow_mut()
+ }
+
+ /// Get a mutable reference through a [`MutableOnDemand`] for read-write access.
+ pub fn get_ref<T>(v: &RefCell<T>) -> RefGuard<'_, T> {
+ v.borrow()
+ }
+
+ /// Downgrade a handle previously obtained with [`upgrade_ref_to_mut()`] to drop mutation support.
+ pub fn downgrade_mut_to_ref<'a, T>(v: RefMut<'a, T>, orig: &'a RefCell<T>) -> RefGuard<'a, T> {
+ drop(v);
+ orig.borrow()
+ }
+
+ /// Map a read guard into a sub-type it contains.
+ pub fn map_ref<T, U: ?Sized>(v: RefGuard<'_, T>, f: impl FnOnce(&T) -> &U) -> MappedRefGuard<'_, U> {
+ Ref::map(v, f)
+ }
+}
+
+pub use _impl::*;
diff --git a/vendor/gix-features/src/zlib/mod.rs b/vendor/gix-features/src/zlib/mod.rs
new file mode 100644
index 000000000..8dcdfd93f
--- /dev/null
+++ b/vendor/gix-features/src/zlib/mod.rs
@@ -0,0 +1,47 @@
+pub use flate2::{Decompress, Status};
+
+/// non-streaming interfaces for decompression
+pub mod inflate {
+ /// The error returned by various [Inflate methods][super::Inflate]
+ #[derive(Debug, thiserror::Error)]
+ #[allow(missing_docs)]
+ pub enum Error {
+ #[error("Could not write all bytes when decompressing content")]
+ WriteInflated(#[from] std::io::Error),
+ #[error("Could not decode zip stream, status was '{0:?}'")]
+ Inflate(#[from] flate2::DecompressError),
+ #[error("The zlib status indicated an error, status was '{0:?}'")]
+ Status(flate2::Status),
+ }
+}
+
+/// Decompress a few bytes of a zlib stream without allocation
+pub struct Inflate {
+ /// The actual decompressor doing all the work.
+ pub state: Decompress,
+}
+
+impl Default for Inflate {
+ fn default() -> Self {
+ Inflate {
+ state: Decompress::new(true),
+ }
+ }
+}
+
+impl Inflate {
+ /// Run the decompressor exactly once. Cannot be run multiple times
+ pub fn once(&mut self, input: &[u8], out: &mut [u8]) -> Result<(flate2::Status, usize, usize), inflate::Error> {
+ let before_in = self.state.total_in();
+ let before_out = self.state.total_out();
+ let status = self.state.decompress(input, out, flate2::FlushDecompress::None)?;
+ Ok((
+ status,
+ (self.state.total_in() - before_in) as usize,
+ (self.state.total_out() - before_out) as usize,
+ ))
+ }
+}
+
+///
+pub mod stream;
diff --git a/vendor/gix-features/src/zlib/stream/deflate/mod.rs b/vendor/gix-features/src/zlib/stream/deflate/mod.rs
new file mode 100644
index 000000000..55f575ea4
--- /dev/null
+++ b/vendor/gix-features/src/zlib/stream/deflate/mod.rs
@@ -0,0 +1,96 @@
+use flate2::Compress;
+
+const BUF_SIZE: usize = 4096 * 8;
+
+/// A utility to zlib compress anything that is written via its [Write][std::io::Write] implementation.
+///
+/// Be sure to call `flush()` when done to finalize the deflate stream.
+pub struct Write<W> {
+ compressor: Compress,
+ inner: W,
+ buf: [u8; BUF_SIZE],
+}
+
+mod impls {
+ use std::io;
+
+ use flate2::{Compress, Compression, FlushCompress, Status};
+
+ use crate::zlib::stream::deflate;
+
+ impl<W> deflate::Write<W>
+ where
+ W: io::Write,
+ {
+ /// Create a new instance writing compressed bytes to `inner`.
+ pub fn new(inner: W) -> deflate::Write<W> {
+ deflate::Write {
+ compressor: Compress::new(Compression::fast(), true),
+ inner,
+ buf: [0; deflate::BUF_SIZE],
+ }
+ }
+
+ /// Reset the compressor, starting a new compression stream.
+ ///
+ /// That way multiple streams can be written to the same inner writer.
+ pub fn reset(&mut self) {
+ self.compressor.reset();
+ }
+
+ /// Consume `self` and return the inner writer.
+ pub fn into_inner(self) -> W {
+ self.inner
+ }
+
+ fn write_inner(&mut self, mut buf: &[u8], flush: FlushCompress) -> io::Result<usize> {
+ let total_in_when_start = self.compressor.total_in();
+ loop {
+ let last_total_in = self.compressor.total_in();
+ let last_total_out = self.compressor.total_out();
+
+ let status = self
+ .compressor
+ .compress(buf, &mut self.buf, flush)
+ .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
+
+ let written = self.compressor.total_out() - last_total_out;
+ if written > 0 {
+ self.inner.write_all(&self.buf[..written as usize])?;
+ }
+
+ match status {
+ Status::StreamEnd => return Ok((self.compressor.total_in() - total_in_when_start) as usize),
+ Status::Ok | Status::BufError => {
+ let consumed = self.compressor.total_in() - last_total_in;
+ buf = &buf[consumed as usize..];
+
+ // output buffer still makes progress
+ if self.compressor.total_out() > last_total_out {
+ continue;
+ }
+ // input still makes progress
+ if self.compressor.total_in() > last_total_in {
+ continue;
+ }
+ // input also makes no progress anymore, need more so leave with what we have
+ return Ok((self.compressor.total_in() - total_in_when_start) as usize);
+ }
+ }
+ }
+ }
+ }
+
+ impl<W: io::Write> io::Write for deflate::Write<W> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.write_inner(buf, FlushCompress::None)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.write_inner(&[], FlushCompress::Finish).map(|_| ())
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/vendor/gix-features/src/zlib/stream/deflate/tests.rs b/vendor/gix-features/src/zlib/stream/deflate/tests.rs
new file mode 100644
index 000000000..ba0dd2a2c
--- /dev/null
+++ b/vendor/gix-features/src/zlib/stream/deflate/tests.rs
@@ -0,0 +1,101 @@
+mod deflate_stream {
+ use std::{
+ io,
+ io::{Read, Write},
+ };
+
+ use bstr::ByteSlice;
+ use flate2::Decompress;
+
+ use crate::zlib::stream::deflate;
+
+ /// Provide streaming decompression using the `std::io::Read` trait.
+ /// If `std::io::BufReader` is used, an allocation for the input buffer will be performed.
+ struct InflateReader<R> {
+ inner: R,
+ decompressor: Decompress,
+ }
+
+ impl<R> InflateReader<R>
+ where
+ R: io::BufRead,
+ {
+ pub fn from_read(read: R) -> InflateReader<R> {
+ InflateReader {
+ decompressor: Decompress::new(true),
+ inner: read,
+ }
+ }
+ }
+
+ impl<R> io::Read for InflateReader<R>
+ where
+ R: io::BufRead,
+ {
+ fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
+ crate::zlib::stream::inflate::read(&mut self.inner, &mut self.decompressor, into)
+ }
+ }
+
+ #[test]
+ fn small_file_decompress() -> Result<(), Box<dyn std::error::Error>> {
+ fn fixture_path(path: &str) -> std::path::PathBuf {
+ std::path::PathBuf::from("tests/fixtures").join(path)
+ }
+ let r = InflateReader::from_read(io::BufReader::new(std::fs::File::open(fixture_path(
+ "objects/37/d4e6c5c48ba0d245164c4e10d5f41140cab980",
+ ))?));
+ let mut bytes = r.bytes();
+ let content = bytes.by_ref().take(16).collect::<Result<Vec<_>, _>>()?;
+ assert_eq!(content.as_slice().as_bstr(), b"blob 9\0hi there\n".as_bstr());
+ assert!(bytes.next().is_none());
+ Ok(())
+ }
+
+ #[test]
+ fn all_at_once() -> Result<(), Box<dyn std::error::Error>> {
+ let mut w = deflate::Write::new(Vec::new());
+ assert_eq!(w.write(b"hello")?, 5);
+ w.flush()?;
+
+ let out = w.inner;
+ assert!(out.len() == 12 || out.len() == 13);
+
+ assert_deflate_buffer(out, b"hello")
+ }
+
+ fn assert_deflate_buffer(out: Vec<u8>, expected: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
+ let mut actual = Vec::new();
+ InflateReader::from_read(out.as_slice()).read_to_end(&mut actual)?;
+ assert_eq!(actual, expected);
+ Ok(())
+ }
+
+ #[test]
+ fn big_file_small_writes() -> Result<(), Box<dyn std::error::Error>> {
+ let mut w = deflate::Write::new(Vec::new());
+ let bytes = include_bytes!(
+ "../../../../tests/fixtures/objects/pack/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack"
+ );
+ for chunk in bytes.chunks(2) {
+ assert_eq!(w.write(chunk)?, chunk.len());
+ }
+ w.flush()?;
+
+ assert_deflate_buffer(w.inner, bytes)
+ }
+
+ #[test]
+ fn big_file_a_few_big_writes() -> Result<(), Box<dyn std::error::Error>> {
+ let mut w = deflate::Write::new(Vec::new());
+ let bytes = include_bytes!(
+ "../../../../tests/fixtures/objects/pack/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack"
+ );
+ for chunk in bytes.chunks(4096 * 9) {
+ assert_eq!(w.write(chunk)?, chunk.len());
+ }
+ w.flush()?;
+
+ assert_deflate_buffer(w.inner, bytes)
+ }
+}
diff --git a/vendor/gix-features/src/zlib/stream/inflate.rs b/vendor/gix-features/src/zlib/stream/inflate.rs
new file mode 100644
index 000000000..007ecedc6
--- /dev/null
+++ b/vendor/gix-features/src/zlib/stream/inflate.rs
@@ -0,0 +1,57 @@
+use std::{io, io::BufRead};
+
+use flate2::{Decompress, FlushDecompress, Status};
+
+/// The boxed variant is faster for what we do (moving the decompressor in and out a lot)
+pub struct ReadBoxed<R> {
+ /// The reader from which bytes should be decompressed.
+ pub inner: R,
+ /// The decompressor doing all the work.
+ pub decompressor: Box<Decompress>,
+}
+
+impl<R> io::Read for ReadBoxed<R>
+where
+ R: BufRead,
+{
+ fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
+ read(&mut self.inner, &mut self.decompressor, into)
+ }
+}
+
+/// Read bytes from `rd` and decompress them using `state` into a pre-allocated fitting buffer `dst`, returning the amount of bytes written.
+pub fn read(rd: &mut impl BufRead, state: &mut Decompress, mut dst: &mut [u8]) -> io::Result<usize> {
+ let mut total_written = 0;
+ loop {
+ let (written, consumed, ret, eof);
+ {
+ let input = rd.fill_buf()?;
+ eof = input.is_empty();
+ let before_out = state.total_out();
+ let before_in = state.total_in();
+ let flush = if eof {
+ FlushDecompress::Finish
+ } else {
+ FlushDecompress::None
+ };
+ ret = state.decompress(input, dst, flush);
+ written = (state.total_out() - before_out) as usize;
+ total_written += written;
+ dst = &mut dst[written..];
+ consumed = (state.total_in() - before_in) as usize;
+ }
+ rd.consume(consumed);
+
+ match ret {
+ // The stream has officially ended, nothing more to do here.
+ Ok(Status::StreamEnd) => return Ok(total_written),
+ // Either input our output are depleted even though the stream is not depleted yet.
+ Ok(Status::Ok) | Ok(Status::BufError) if eof || dst.is_empty() => return Ok(total_written),
+ // Some progress was made in both the input and the output, it must continue to reach the end.
+ Ok(Status::Ok) | Ok(Status::BufError) if consumed != 0 || written != 0 => continue,
+ // A strange state, where zlib makes no progress but isn't done either. Call it out.
+ Ok(Status::Ok) | Ok(Status::BufError) => unreachable!("Definitely a bug somewhere"),
+ Err(..) => return Err(io::Error::new(io::ErrorKind::InvalidInput, "corrupt deflate stream")),
+ }
+ }
+}
diff --git a/vendor/gix-features/src/zlib/stream/mod.rs b/vendor/gix-features/src/zlib/stream/mod.rs
new file mode 100644
index 000000000..7fb239d36
--- /dev/null
+++ b/vendor/gix-features/src/zlib/stream/mod.rs
@@ -0,0 +1,4 @@
+///
+pub mod deflate;
+///
+pub mod inflate;
diff --git a/vendor/gix-features/tests/hash.rs b/vendor/gix-features/tests/hash.rs
new file mode 100644
index 000000000..c8e48da57
--- /dev/null
+++ b/vendor/gix-features/tests/hash.rs
@@ -0,0 +1,13 @@
+use gix_features::hash::Sha1;
+
+#[cfg(not(feature = "fast-sha1"))]
+#[test]
+fn size_of_sha1() {
+ assert_eq!(std::mem::size_of::<Sha1>(), 96)
+}
+
+#[cfg(feature = "fast-sha1")]
+#[test]
+fn size_of_sha1() {
+ assert_eq!(std::mem::size_of::<Sha1>(), 104)
+}
diff --git a/vendor/gix-features/tests/parallel/in_order_iter.rs b/vendor/gix-features/tests/parallel/in_order_iter.rs
new file mode 100644
index 000000000..9e1881215
--- /dev/null
+++ b/vendor/gix-features/tests/parallel/in_order_iter.rs
@@ -0,0 +1,54 @@
+use std::convert::Infallible;
+
+use gix_features::parallel::InOrderIter;
+
+#[test]
+fn in_order_stays_in_order() {
+ assert_eq!(
+ InOrderIter::from(vec![Ok::<_, Infallible>((0usize, 'a')), Ok((1, 'b')), Ok((2, 'c'))].into_iter())
+ .collect::<Result<Vec<_>, _>>()
+ .expect("infallible"),
+ vec!['a', 'b', 'c']
+ )
+}
+
+#[test]
+fn out_of_order_items_are_held_until_the_sequence_is_complete() {
+ assert_eq!(
+ InOrderIter::from(
+ vec![
+ Ok::<_, Infallible>((2usize, 'c')),
+ Ok((1, 'b')),
+ Ok((0, 'a')),
+ Ok((3, 'd'))
+ ]
+ .into_iter()
+ )
+ .collect::<Result<Vec<_>, _>>()
+ .expect("infallible"),
+ vec!['a', 'b', 'c', 'd']
+ )
+}
+
+#[test]
+fn in_sequence_errors_immediately_trigger_a_fuse() {
+ let mut iter = InOrderIter::from(vec![Ok::<_, &'static str>((0usize, 'a')), Err("err"), Ok((1, 'b'))].into_iter());
+ assert_eq!(iter.next(), Some(Ok('a')));
+ assert_eq!(iter.next(), Some(Err("err")));
+ assert_eq!(
+ iter.next(),
+ None,
+ "fuse should have triggered so we don't see anything else"
+ );
+}
+
+#[test]
+fn out_of_sequence_errors_immediately_trigger_a_fuse() {
+ let mut iter = InOrderIter::from(vec![Ok::<_, &'static str>((1usize, 'b')), Err("err"), Ok((0, 'a'))].into_iter());
+ assert_eq!(iter.next(), Some(Err("err")));
+ assert_eq!(
+ iter.next(),
+ None,
+ "fuse should have triggered so we don't see anything else"
+ );
+}
diff --git a/vendor/gix-features/tests/parallel/mod.rs b/vendor/gix-features/tests/parallel/mod.rs
new file mode 100644
index 000000000..b4b4236f8
--- /dev/null
+++ b/vendor/gix-features/tests/parallel/mod.rs
@@ -0,0 +1,125 @@
+//! Tests that are working similarly in parallel and serial mode
+use gix_features::parallel;
+
+mod in_order_iter;
+
+#[derive(Default)]
+struct Adder {
+ count: usize,
+}
+
+impl parallel::Reduce for Adder {
+ type Input = usize;
+ type FeedProduce = usize;
+ type Output = usize;
+ type Error = ();
+
+ fn feed(&mut self, item: Self::Input) -> Result<Self::FeedProduce, Self::Error> {
+ self.count += item;
+ Ok(item)
+ }
+
+ fn finalize(self) -> Result<Self::Output, Self::Error> {
+ Ok(self.count)
+ }
+}
+
+#[test]
+fn in_parallel() {
+ let res = parallel::in_parallel(
+ std::iter::from_fn(|| Some(1)).take(100),
+ None,
+ |_n| (),
+ |input, _state| input,
+ Adder::default(),
+ )
+ .expect("successful computation");
+ assert_eq!(res, 100);
+}
+
+#[test]
+fn in_parallel_with_mut_slice_in_chunks() {
+ let num_items = 33;
+ let mut input: Vec<_> = std::iter::repeat(1).take(num_items).collect();
+ let counts = parallel::in_parallel_with_slice(
+ &mut input,
+ None,
+ |_| 0usize,
+ |item, acc| {
+ *acc += *item;
+ *item += 1;
+ Ok::<_, ()>(())
+ },
+ || Some(std::time::Duration::from_millis(10)),
+ std::convert::identity,
+ )
+ .unwrap();
+ let expected = std::iter::repeat(1).take(num_items).sum::<usize>();
+ assert_eq!(counts.iter().sum::<usize>(), expected);
+ assert_eq!(input.iter().sum::<usize>(), expected * 2, "we increment each entry");
+}
+
+#[test]
+fn stepped_reduce_next() {
+ let mut iter = parallel::reduce::Stepwise::new(
+ std::iter::from_fn(|| Some(1)).take(100),
+ None,
+ |_n| (),
+ |input, _state| input,
+ Adder::default(),
+ );
+
+ let mut aggregate = 0;
+ for value in iter.by_ref() {
+ aggregate += value.expect("success");
+ }
+ assert_eq!(aggregate, 100);
+}
+
+#[test]
+fn stepped_reduce_ref_input_and_consume() {
+ let seq = std::sync::Arc::new(vec![0usize, 1, 2]);
+ struct ArcIter(std::sync::Arc<Vec<usize>>, usize);
+ impl Iterator for ArcIter {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let n = self.0.get(self.1).copied();
+ self.1 += 1;
+ n
+ }
+ }
+
+ let mut iter = parallel::reduce::Stepwise::new(
+ ArcIter(seq.clone(), 0).enumerate(),
+ None,
+ {
+ let seq = std::sync::Arc::clone(&seq);
+ move |_n| seq.len()
+ },
+ {
+ let seq = std::sync::Arc::clone(&seq);
+ move |(idx, ref_val): (usize, usize), _state| seq[idx] * ref_val
+ },
+ Adder::default(),
+ );
+
+ let mut aggregate = 0;
+ for value in iter.by_ref() {
+ aggregate += value.expect("success");
+ }
+ assert_eq!(aggregate, 5);
+}
+
+#[test]
+fn stepped_reduce_finalize() {
+ let iter = parallel::reduce::Stepwise::new(
+ std::iter::from_fn(|| Some(1)).take(100),
+ None,
+ |_n| (),
+ |input, _state| input,
+ Adder::default(),
+ );
+
+ assert_eq!(iter.finalize().expect("success"), 100);
+}
diff --git a/vendor/gix-features/tests/parallel_shared.rs b/vendor/gix-features/tests/parallel_shared.rs
new file mode 100644
index 000000000..055a899ea
--- /dev/null
+++ b/vendor/gix-features/tests/parallel_shared.rs
@@ -0,0 +1 @@
+mod parallel;
diff --git a/vendor/gix-features/tests/parallel_shared_threaded.rs b/vendor/gix-features/tests/parallel_shared_threaded.rs
new file mode 100644
index 000000000..055a899ea
--- /dev/null
+++ b/vendor/gix-features/tests/parallel_shared_threaded.rs
@@ -0,0 +1 @@
+mod parallel;
diff --git a/vendor/gix-features/tests/parallel_threaded.rs b/vendor/gix-features/tests/parallel_threaded.rs
new file mode 100644
index 000000000..05f49d195
--- /dev/null
+++ b/vendor/gix-features/tests/parallel_threaded.rs
@@ -0,0 +1,122 @@
+mod optimize_chunk_size_and_thread_limit {
+ use gix_features::parallel::optimize_chunk_size_and_thread_limit;
+
+ #[test]
+ fn not_enough_chunks_for_threads() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, Some(10), None, Some(10)),
+ (1, Some(5), 5)
+ );
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, Some(10), Some(3), Some(10)),
+ (1, Some(3), 3),
+ "the thread limit is always respected"
+ );
+ }
+
+ #[test]
+ fn some_more_chunks_per_thread() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, Some(30), None, Some(10)),
+ (1, Some(10), 10)
+ );
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, Some(30), Some(5), Some(10)),
+ (3, Some(5), 5),
+ "the thread limit is always respected"
+ );
+ }
+
+ #[test]
+ fn chunk_size_too_small() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, Some(100), None, Some(10)),
+ (5, Some(10), 10)
+ );
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, Some(100), Some(5), Some(10)),
+ (10, Some(5), 5),
+ "the thread limit is always respected"
+ );
+ }
+
+ #[test]
+ fn chunk_size_too_big() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(50, Some(100), None, Some(10)),
+ (5, Some(10), 10)
+ );
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(50, Some(100), Some(5), Some(10)),
+ (10, Some(5), 5),
+ "the thread limit is always respected"
+ );
+ }
+
+ mod unknown_chunk_count {
+ use gix_features::parallel::optimize_chunk_size_and_thread_limit;
+
+ #[test]
+ fn medium_chunk_size_many_threads() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(50, None, None, Some(4)),
+ (50, Some(4), 4),
+ "really, what do we know"
+ );
+ }
+
+ #[test]
+ fn medium_chunk_size_single_thread() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(50, None, None, Some(1)),
+ (50, Some(1), 1),
+ "single threaded - we don't touch that"
+ );
+ }
+
+ #[test]
+ fn small_chunk_size_single_thread() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, None, None, Some(1)),
+ (1, Some(1), 1),
+ "single threaded - we don't touch that"
+ );
+ }
+
+ #[test]
+ fn small_chunk_size_many_threads() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, None, None, Some(4)),
+ (50, Some(4), 4),
+ "we prefer an arbitrary number, which should really be based on effort, but the caller has to adjust for that"
+ );
+ }
+ }
+
+ mod real_values {
+ use gix_features::parallel::optimize_chunk_size_and_thread_limit;
+
+ #[test]
+ fn linux_kernel_pack_my_machine_lookup() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(10000, Some(7_500_000), None, Some(4)),
+ (1000, Some(4), 4),
+ "the bucket size is capped actually, somewhat arbitrarily"
+ );
+ }
+
+ #[test]
+ fn linux_kernel_pack_my_machine_indexed() {
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(1, None, None, Some(4)),
+ (50, Some(4), 4),
+ "low values are raised to arbitrary value"
+ );
+ assert_eq!(
+ optimize_chunk_size_and_thread_limit(10000, None, None, Some(4)),
+ (1000, Some(4), 4),
+ "high values are capped"
+ );
+ }
+ }
+}
diff --git a/vendor/gix-features/tests/pipe.rs b/vendor/gix-features/tests/pipe.rs
new file mode 100644
index 000000000..4815000bf
--- /dev/null
+++ b/vendor/gix-features/tests/pipe.rs
@@ -0,0 +1,117 @@
+mod io {
+ use std::io::{BufRead, ErrorKind, Read, Write};
+
+ use gix_features::io;
+
+ #[test]
+ fn threaded_read_to_end() {
+ let (mut writer, mut reader) = gix_features::io::pipe::unidirectional(0);
+
+ let message = "Hello, world!";
+ std::thread::spawn(move || {
+ writer
+ .write_all(message.as_bytes())
+ .expect("writes to work if reader is present")
+ });
+
+ let mut received = String::new();
+ reader.read_to_string(&mut received).unwrap();
+
+ assert_eq!(&received, message);
+ }
+
+ #[test]
+ fn lack_of_reader_fails_with_broken_pipe() {
+ let (mut writer, _) = io::pipe::unidirectional(None);
+ assert_eq!(
+ writer.write_all(b"must fail").unwrap_err().kind(),
+ ErrorKind::BrokenPipe
+ );
+ }
+ #[test]
+ fn line_reading_one_by_one() {
+ let (mut writer, mut reader) = io::pipe::unidirectional(2);
+ writer.write_all(b"a\n").expect("success");
+ writer.write_all(b"b\nc").expect("success");
+ drop(writer);
+ let mut buf = String::new();
+ for expected in &["a\n", "b\n", "c"] {
+ buf.clear();
+ assert_eq!(reader.read_line(&mut buf).expect("success"), expected.len());
+ assert_eq!(buf, *expected);
+ }
+ }
+
+ #[test]
+ fn line_reading() {
+ let (mut writer, reader) = io::pipe::unidirectional(2);
+ writer.write_all(b"a\n").expect("success");
+ writer.write_all(b"b\nc\n").expect("success");
+ drop(writer);
+ assert_eq!(
+ reader.lines().flat_map(Result::ok).collect::<Vec<_>>(),
+ vec!["a", "b", "c"]
+ )
+ }
+
+ #[test]
+ fn writer_can_inject_errors() {
+ let (writer, mut reader) = io::pipe::unidirectional(1);
+ writer
+ .channel
+ .send(Err(std::io::Error::new(std::io::ErrorKind::Other, "the error")))
+ .expect("send success");
+ let mut buf = [0];
+ assert_eq!(
+ reader.read(&mut buf).unwrap_err().to_string(),
+ "the error",
+ "using Read trait, errors are propagated"
+ );
+
+ writer
+ .channel
+ .send(Err(std::io::Error::new(std::io::ErrorKind::Other, "the error")))
+ .expect("send success");
+ assert_eq!(
+ reader.fill_buf().unwrap_err().to_string(),
+ "the error",
+ "using BufRead trait, errors are propagated"
+ );
+ }
+
+ #[test]
+ fn continue_on_empty_writes() {
+ let (mut writer, mut reader) = io::pipe::unidirectional(2);
+ writer.write_all(&[]).expect("write successful and non-blocking");
+ let input = b"hello";
+ writer
+ .write_all(input)
+ .expect("second write works as well as there is capacity");
+ let mut buf = vec![0u8; input.len()];
+ assert_eq!(reader.read(&mut buf).expect("read succeeds"), input.len());
+ assert_eq!(buf, &input[..]);
+ }
+
+ #[test]
+ fn small_reads() {
+ const BLOCK_SIZE: usize = 20;
+ let block_count = 20;
+ let (mut writer, mut reader) = io::pipe::unidirectional(Some(4));
+ std::thread::spawn(move || {
+ for _ in 0..block_count {
+ let data = &[0; BLOCK_SIZE];
+ writer.write_all(data).unwrap();
+ }
+ });
+
+ let mut small_read_buf = [0; BLOCK_SIZE / 2];
+ let mut bytes_read = 0;
+ while let Ok(size) = reader.read(&mut small_read_buf) {
+ if size == 0 {
+ break;
+ }
+ bytes_read += size;
+ }
+ assert_eq!(block_count * BLOCK_SIZE, bytes_read);
+ }
+}