diff options
Diffstat (limited to 'vendor/gix-object')
24 files changed, 889 insertions, 447 deletions
diff --git a/vendor/gix-object/.cargo-checksum.json b/vendor/gix-object/.cargo-checksum.json index 3a93277c9..1c2d578fd 100644 --- a/vendor/gix-object/.cargo-checksum.json +++ b/vendor/gix-object/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"0a6fbe95856f74ab9bdd684f980e527d67ab48beadd4a82053bebc0a906ddbb3","Cargo.toml":"942bb2e0babb07344a6aacc52bc8e407a090f1c5ef055f7c05de366e9e51a2cc","LICENSE-APACHE":"cb4780590812826851ba250f90bed0ed19506ec98f6865a0e2e20bbf62391ff9","LICENSE-MIT":"49df47913ab2beafe8dc45607877ae64198bf0eee64aaad3e82ed9e4d27424e8","src/blob.rs":"edbca29c4ec33e6791cc3730a70f38e8208e2e8eb1132059417886d05bab1bdd","src/commit/decode.rs":"38aa68f434af6e2512e5c13a12609d998cd5f44dcef0c5769c8f6ab387770b41","src/commit/message/body.rs":"dc5a3ec62cb87106a69e129c35a146e3807afacaee6c213120cf32d28e2c9f66","src/commit/message/decode.rs":"87e517c3c43d016b576441e019882f90e2b8096a7c3bad0e97d8660a934b4a3d","src/commit/message/mod.rs":"3c88e53583cbbc8606ba400bba3d54f2ce6fa75ce4c78d73e2d8bae2b8f45046","src/commit/mod.rs":"795bfd51cfba279f19eb0ba0da55e944e959c52476789cba7980c06bf1b1d545","src/commit/ref_iter.rs":"adcb43df9f75e986299b22fa37e51cd8bc0b2bede0871becf6eed3b78d999e81","src/commit/write.rs":"ac3e509d7caba8ff86fc3cd645a49c1752fc72b527fd7c7e6ff7aedf72e2b49a","src/data.rs":"552de5b87260936e69bff1ef2b6d93fe46d21bc05db84cac591caa0b5678bb95","src/encode.rs":"1be2616935ed333d8a7774debccc417b5d621c8ea30748768594706b813e7337","src/kind.rs":"1e47c1fa52d4dddf684976155f802af4acab6a1b055735604e7a4c0e44b5fd7c","src/lib.rs":"9ce082fa7117fbb1025054eb33676a22d9b58563fdec6f6071936b8455e30ce9","src/object/convert.rs":"5fa061ce08c12cd59cc5e6975c9e6b57a5ac596c5fe63eeb5758080e7dd7a328","src/object/mod.rs":"bf08ec2e20c1bc6f5eef49b16084c3ff86f44fed62276c7095e1a8ad315b4dfc","src/parse.rs":"da918868adb3ff7ea6212c284523028fb70ff7220a2fcd51eb3ab5a9b29658a5","src/tag/decode.rs":"77adf29167b2f6af9ed511881da2da244ac2284c97485ccae1fba985d3ff4fac","src/tag/mod.rs":"49743fd37efcafac49e693c54a0a304ad05dbe7b559e46c4fb29ef804e77a9b5","src/tag/ref_iter.rs":"4d7809ab445f920ca41e9251205223a95dbf61f23435189d010694202927c196","src/tag/write.rs":"0cbd581cd9fc331035aa5e591f8fda84ce5515b49a0b2ca768c89b3e2236659b","src/tag/write/tests.rs":"e3c3674d73d3436f10c268154b9362eb380ff9c014b6db2a141bd0a0747c4aff","src/traits.rs":"aa3fad21ffabad389584bb7254d60f4ef1b8165c7ef6e9967a133a1e35fd1fe1","src/tree/mod.rs":"478a7562fb5139e0f2877f92fe3cb9aa144e6d3aa8150e691f62cf05d4b186bb","src/tree/ref_iter.rs":"f2ea2f2af927a44def2795e0fe536c758f38a7a6f232802595f50d102a895ca6","src/tree/write.rs":"a865a399c386b8bbc784ab405fe066169cd5d3f4990ec815afe5c3129b4f1f1b"},"package":"8926c8f51c44dec3e709cb5dbc93deb9e8d4064c43c9efc54c158dcdfe8446c7"}
\ No newline at end of file +{"files":{"CHANGELOG.md":"df234e21d8d0bc316a0ac6adeacbd901b965acd9bdad0b9454ac36e19567ffbb","Cargo.toml":"778daa8a0e3e036dce919a051c716d0138326a771922a3d6f7c048ef3ed1e013","LICENSE-APACHE":"cb4780590812826851ba250f90bed0ed19506ec98f6865a0e2e20bbf62391ff9","LICENSE-MIT":"49df47913ab2beafe8dc45607877ae64198bf0eee64aaad3e82ed9e4d27424e8","src/blob.rs":"498e4d4d54c2ba9455614f3e0b06b6b9bbfcfd1fab2b4a18371f791114ba494c","src/commit/decode.rs":"d63699485135c2100459cf3683f24c24edf9f8b214076585a1423747d0ea5efc","src/commit/message/body.rs":"3ada2e797423756202e86db398fefc704fcaf6e42b4d8fe42ca839b14863b883","src/commit/message/decode.rs":"df0dd08b400c030dbf3a9da3733c2e5199423c643db4f3bfd4f58832c2d9d4ff","src/commit/message/mod.rs":"3c88e53583cbbc8606ba400bba3d54f2ce6fa75ce4c78d73e2d8bae2b8f45046","src/commit/mod.rs":"81b8f7305945de51cc4d828d53837b7e013e68c4a8d896d445fe29972a6bca03","src/commit/ref_iter.rs":"3f1216d00b7bcfd0bd9eff3ee767f706b42472aa429246375fc770b543dbac84","src/commit/write.rs":"18df601baab03e03ab414b91631087c46dab63f6d6a46fd1fbf04b6b55f1edb8","src/data.rs":"fd1f9281274855d26570d866335ebf5f27709a80308f3c4e5da26a0e7db4be5c","src/encode.rs":"cac3ac7a9263f31e2b19a434938607500ac3256b6bd3bf9ffa24dd6ef401b3a3","src/kind.rs":"f6af54494ddf2e42d07e1ebbc2aad25a3e291f0e7275618ab0758d8802963ca5","src/lib.rs":"509f5326ae54c9f5ad0d65bf701d44b98c57fe735604a55d6c45519bee2b83cd","src/object/convert.rs":"5fa061ce08c12cd59cc5e6975c9e6b57a5ac596c5fe63eeb5758080e7dd7a328","src/object/mod.rs":"81ec0da8639b2339c809a84057582efaf5776d48e39e9b00a2af6bbb794eab1c","src/parse.rs":"3e4095cd579aa216e42dc3bb63d01b21c8e8b12d07faa09786fac0950a3d138e","src/tag/decode.rs":"090a128e1c1bebb69633e6e6bda9cf501b606e491be5bb7f9c3ce3f6bd8ab4c1","src/tag/mod.rs":"9532c15c6e90428dffe7dd80bcfe8bea2fd3210e43e0d4b583f7813a8bae4fe5","src/tag/ref_iter.rs":"b7df75f1555dacddaf0b83777e2281679163b52f3cf086b33b24af4b0b582caa","src/tag/write.rs":"61f92cfe525137da564b24816b806da65f45168a0880de1fbbd4899929460d5e","src/tag/write/tests.rs":"e3c3674d73d3436f10c268154b9362eb380ff9c014b6db2a141bd0a0747c4aff","src/traits.rs":"279302ec53f7bfce2aefba1967acd1c033b66199df622c589c65f146e5036ce6","src/tree/mod.rs":"2e3c330b0947d2e24fa7b5ad58690261d313a705671fd97834278fa72a10e39f","src/tree/ref_iter.rs":"2c2c106550cdd21f6a5340abfb8e95661f240130cc4a5346989b67c1c1d6ace8","src/tree/write.rs":"02c68d954428805f59e4407586337c6fe8265e7a80e20bb83f8fe88fe0e0cf9a"},"package":"1e7e19616c67967374137bae83e950e9b518a9ea8a605069bd6716ada357fd6f"}
\ No newline at end of file diff --git a/vendor/gix-object/CHANGELOG.md b/vendor/gix-object/CHANGELOG.md index 9a6b735a6..c88bda31d 100644 --- a/vendor/gix-object/CHANGELOG.md +++ b/vendor/gix-object/CHANGELOG.md @@ -5,6 +5,309 @@ 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.37.0 (2023-09-24) + +A maintenance release without user-facing changes. + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 1 commit contributed to the release. + - 16 days passed between releases. + - 0 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** + - Prepare changelogs prior to release ([`8a60d5b`](https://github.com/Byron/gitoxide/commit/8a60d5b80877c213c3b646d3061e8a33e0e433ec)) +</details> + +## 0.36.0 (2023-09-08) + +### Bug Fixes (BREAKING) + + - <csr-id-072ee32f693a31161cd6a843da6582d13efbb20b/> use `dyn` trait where possible. + This reduces compile time due to avoiding duplication. + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 5 commits contributed to the release over the course of 17 calendar days. + - 17 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.8.0, gix-hash v0.13.0, gix-features v0.34.0, gix-actor v0.26.0, gix-object v0.36.0, gix-path v0.10.0, gix-glob v0.12.0, gix-attributes v0.18.0, gix-packetline-blocking v0.16.6, gix-filter v0.4.0, gix-fs v0.6.0, gix-commitgraph v0.20.0, gix-hashtable v0.4.0, gix-revwalk v0.7.0, gix-traverse v0.32.0, gix-worktree-stream v0.4.0, gix-archive v0.4.0, gix-config-value v0.14.0, gix-tempfile v9.0.0, gix-lock v9.0.0, gix-ref v0.36.0, gix-sec v0.10.0, gix-config v0.29.0, gix-prompt v0.7.0, gix-url v0.23.0, gix-credentials v0.19.0, gix-diff v0.35.0, gix-discover v0.24.0, gix-ignore v0.7.0, gix-index v0.24.0, gix-macros v0.1.0, gix-mailmap v0.18.0, gix-negotiate v0.7.0, gix-pack v0.42.0, gix-odb v0.52.0, gix-pathspec v0.2.0, gix-packetline v0.16.6, gix-transport v0.36.0, gix-protocol v0.39.0, gix-revision v0.21.0, gix-refspec v0.17.0, gix-submodule v0.3.0, gix-worktree v0.25.0, gix-worktree-state v0.2.0, gix v0.53.0, safety bump 39 crates ([`8bd0456`](https://github.com/Byron/gitoxide/commit/8bd045676bb2cdc02624ab93e73ff8518064ca38)) + - Prepare changelogs for release ([`375db06`](https://github.com/Byron/gitoxide/commit/375db06a8442378c3f7a922fae38e2a6694d9d04)) + - Merge branch `dyn`ification ([`f658fcc`](https://github.com/Byron/gitoxide/commit/f658fcc52dc2200ae34ca53dc10be97fb9012057)) + - Use `dyn` trait where possible. ([`072ee32`](https://github.com/Byron/gitoxide/commit/072ee32f693a31161cd6a843da6582d13efbb20b)) + - Merge branch 'gix-submodule' ([`363ee77`](https://github.com/Byron/gitoxide/commit/363ee77400805f473c9ad66eadad9214e7ab66f4)) +</details> + +## 0.35.0 (2023-08-22) + +<csr-id-ef54aab9e5521add4154ee8d902d62612a9d8d4a/> +<csr-id-353b1a788a7c5a627ec73185f841ea4893a147a5/> +<csr-id-7649b185c93877e8c8b3cebedf685be8e94a0d9d/> + +### Chore + + - <csr-id-ef54aab9e5521add4154ee8d902d62612a9d8d4a/> switch `nom` to `winnow` in remaining uses in `gix-object`, `gix-ref`, and `gix-actor` for ~20% more performance. + It's likely that over time, these parsers will get even faster due to improvements to `winnow`. + Thanks, Ed Page, for single-handedly performing this transition. + - <csr-id-353b1a788a7c5a627ec73185f841ea4893a147a5/> add benchmarks to avoid parsing performance regressions + - <csr-id-7649b185c93877e8c8b3cebedf685be8e94a0d9d/> remove unused dependency: 'hex' + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 28 commits contributed to the release over the course of 13 calendar days. + - 15 days passed between releases. + - 3 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-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) + - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) + - Just fmt ([`0d258f4`](https://github.com/Byron/gitoxide/commit/0d258f40afcd848509e2b0c7c264e9f346ed1726)) + - Switch `nom` to `winnow` in remaining uses in `gix-object`, `gix-ref`, and `gix-actor` for ~20% more performance. ([`ef54aab`](https://github.com/Byron/gitoxide/commit/ef54aab9e5521add4154ee8d902d62612a9d8d4a)) + - Refactor and fixes ([`02587fc`](https://github.com/Byron/gitoxide/commit/02587fc879c54b2b3e62ffbe1ab4c29591ea0d80)) + - Upgrade `winnow` to latest patch release ([`8c41848`](https://github.com/Byron/gitoxide/commit/8c4184817e4e4364c34badc8ff0a71c6ae952efd)) + - Remove From<winnow> for (small) step towards stable API ([`be1f4b5`](https://github.com/Byron/gitoxide/commit/be1f4b5d2158fc73d926394d22d62bb597c5e6ce)) + - Make clippy happy ([`62f7bc6`](https://github.com/Byron/gitoxide/commit/62f7bc65c1eef812baa2ef2e5b406762e117b66a)) + - Switch off deprecated VerboseError ([`93fc441`](https://github.com/Byron/gitoxide/commit/93fc441c6c82086e125ace5bdda3b9403d271618)) + - Switch errors to StrContext ([`df226dd`](https://github.com/Byron/gitoxide/commit/df226dd31df2c591c6470ed70098202112e13dae)) + - Minor cleanup possible with 0.5 ([`a07590c`](https://github.com/Byron/gitoxide/commit/a07590cb46423cb0422c18b9fc04b153c0fd53b1)) + - Upgrade to Winnow 0.5 ([`3f8c91f`](https://github.com/Byron/gitoxide/commit/3f8c91fa463fbb53d54b2bf359e0dee7387afa00)) + - Simplify parsers ([`12f03db`](https://github.com/Byron/gitoxide/commit/12f03db6475b92f492f5a14bda472c139c3511e0)) + - Resolve 0.4 not-quite deprecations ([`f0cbf81`](https://github.com/Byron/gitoxide/commit/f0cbf81a346e087a622b0e2a6a37593861d0010f)) + - Resolve 0.4 deprecations ([`9ed7df0`](https://github.com/Byron/gitoxide/commit/9ed7df0a17deed08759dc29fc0089cdea100e433)) + - Upgrade to Winnow 0.4 ([`86ea47f`](https://github.com/Byron/gitoxide/commit/86ea47f28079c51f874b0d662867040b92f88d14)) + - Parse explicitly in prep for 0.4 ([`b3f0418`](https://github.com/Byron/gitoxide/commit/b3f041829881e881ad4eeeacaeea31064c523340)) + - Resolve remaining winnow 0.3 deprecations ([`fee441d`](https://github.com/Byron/gitoxide/commit/fee441da875d52b1a0cb557d2fa58cee9c29e16a)) + - Prefer Parser inherent parsers ([`b37a909`](https://github.com/Byron/gitoxide/commit/b37a909a5c344201a985262351e0fb67757572a4)) + - Prefer built-in Winnow parsers ([`ac0e81c`](https://github.com/Byron/gitoxide/commit/ac0e81c41f8c8a33ede9a0d8b7bffcd04bb97dc3)) + - Simplify winnow ErrMode construction ([`86d7fd1`](https://github.com/Byron/gitoxide/commit/86d7fd18487626d30f6d5478864819a3d7428085)) + - Switch gix to winnow 0.3 ([`ee75de1`](https://github.com/Byron/gitoxide/commit/ee75de1e6035305fc23bdef2522ae5081272ac82)) + - Add benchmarks to avoid parsing performance regressions ([`353b1a7`](https://github.com/Byron/gitoxide/commit/353b1a788a7c5a627ec73185f841ea4893a147a5)) + - Merge branch 'faster-hex' ([`4a4fa0f`](https://github.com/Byron/gitoxide/commit/4a4fa0fcdaa6e14b51d3f03f5d7c5b65042667bf)) + - Remove unused dependency: 'hex' ([`7649b18`](https://github.com/Byron/gitoxide/commit/7649b185c93877e8c8b3cebedf685be8e94a0d9d)) + - Merge branch 'extract-signatures' ([`b37affe`](https://github.com/Byron/gitoxide/commit/b37affefecfb30a94431cd21dae6659004ca6244)) + - Refactor ([`fb95ead`](https://github.com/Byron/gitoxide/commit/fb95eadb2da12c794d41b1f6212eba60ff3dd2dc)) + - Add commit signature extraction ([`2f9c0dd`](https://github.com/Byron/gitoxide/commit/2f9c0ddb7c2191789b4c0a5e8f2bf9253ac58606)) +</details> + +## 0.34.0 (2023-08-07) + +A maintenance release without user-facing changes. + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 4 commits contributed to the release over the course of 3 calendar days. + - 4 days passed between releases. + - 0 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-glob v0.10.2, gix-date v0.7.2, gix-validate v0.8.0, gix-object v0.34.0, gix-ref v0.34.0, gix-config v0.27.0, gix-commitgraph v0.18.2, gix-revwalk v0.5.0, gix-revision v0.19.0, gix-refspec v0.15.0, gix-submodule v0.1.0, safety bump 18 crates ([`4604f83`](https://github.com/Byron/gitoxide/commit/4604f83ef238dc07c85aaeae097399b67f3cfd0c)) + - Prepare changelogs prior to release of `gix-submodule` ([`f3c4311`](https://github.com/Byron/gitoxide/commit/f3c43110e8d5f16cf87e50821044d8b3edbae235)) + - Merge branch 'dev-on-linux' ([`6b4a303`](https://github.com/Byron/gitoxide/commit/6b4a30330fe49fc97daa73f55bf56580cc0597aa)) + - Fix various tests to run properly on linux ([`ef8ccd9`](https://github.com/Byron/gitoxide/commit/ef8ccd9d16143d37155d063747c69cade80f162d)) +</details> + +## 0.33.2 (2023-08-02) + +<csr-id-7f7353e4525adc308e97b82d27bd301e48da6016/> + +### Other + + - <csr-id-7f7353e4525adc308e97b82d27bd301e48da6016/> fix test for struct size for 32-bit architectures + The size of gix_object::Data is 24 bytes only on 64-bit architectures, + on 32-bit architectures it's exactly half that (12 bytes). + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 7 commits contributed to the release. + - 11 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-actor v0.24.2, gix-object v0.33.2, gix-ref v0.33.3, gix-config v0.26.2, gix-prompt v0.5.5, gix-odb v0.50.2, gix-transport v0.34.2, gix-protocol v0.37.0, gix-worktree v0.23.1, gix v0.51.0, safety bump 3 crates ([`231ac1c`](https://github.com/Byron/gitoxide/commit/231ac1c6ad5ca9a84dbeb0dee14bfbf2fef1ae1e)) + - Prepare additional changelogs ([`db63815`](https://github.com/Byron/gitoxide/commit/db6381522395a0de047118e81df5cd3cbeb862b9)) + - Merge branch 'decathorpe/main' ([`422747d`](https://github.com/Byron/gitoxide/commit/422747d35724a56dade73c8d68b8ebcbaa4b9b25)) + - Prepare changelogs ([`e4d2890`](https://github.com/Byron/gitoxide/commit/e4d2890a85bf60e9cdb4016dddfab3c4dccbe75e)) + - Merge branch 'fixes-and-improvements' ([`f8b1f55`](https://github.com/Byron/gitoxide/commit/f8b1f553371f25b1bea6bce7cbb2ff1f01194856)) + - Fix test for struct size for 32-bit architectures ([`7f7353e`](https://github.com/Byron/gitoxide/commit/7f7353e4525adc308e97b82d27bd301e48da6016)) + - Add another very special commit for parsing tests ([`f852243`](https://github.com/Byron/gitoxide/commit/f852243831474a3fd311a0507d11fd43e0f6e4d3)) +</details> + +## 0.33.1 (2023-07-22) + +### New Features + + - <csr-id-424d347bb2466ecdf8cfc9e0da779d604d1f9e4e/> `TreeRef::bisect_entry()` to correctly find an entry by name + - <csr-id-437fedc59c2bad57beb3cf54e4c71a470bd22ee2/> `Copy` for `tree::EntryRef` + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 9 commits contributed to the release over the course of 1 calendar day. + - 3 days passed between releases. + - 2 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.32.1, gix-actor v0.24.1, gix-validate v0.7.7, gix-object v0.33.1, gix-path v0.8.4, gix-glob v0.10.1, gix-quote v0.4.6, gix-attributes v0.16.0, gix-command v0.2.8, gix-packetline-blocking v0.16.4, gix-filter v0.2.0, gix-fs v0.4.1, gix-chunk v0.4.4, gix-commitgraph v0.18.1, gix-hashtable v0.2.4, gix-revwalk v0.4.1, gix-traverse v0.30.1, gix-worktree-stream v0.2.0, gix-archive v0.2.0, gix-config-value v0.12.5, gix-tempfile v7.0.1, gix-utils v0.1.5, gix-lock v7.0.2, gix-ref v0.33.1, gix-sec v0.8.4, gix-prompt v0.5.4, gix-url v0.21.1, gix-credentials v0.17.1, gix-diff v0.33.1, gix-discover v0.22.1, gix-ignore v0.5.1, gix-bitmap v0.2.6, gix-index v0.21.1, gix-mailmap v0.16.1, gix-negotiate v0.5.1, gix-pack v0.40.1, gix-odb v0.50.1, gix-packetline v0.16.4, gix-transport v0.34.1, gix-protocol v0.36.1, gix-revision v0.18.1, gix-refspec v0.14.1, gix-worktree v0.23.0, gix v0.50.0, safety bump 5 crates ([`16295b5`](https://github.com/Byron/gitoxide/commit/16295b58e2581d2e8b8b762816f52baabe871c75)) + - Prepare more changelogs ([`c4cc5f2`](https://github.com/Byron/gitoxide/commit/c4cc5f261d29f712a101033a18293a97a9d4ae85)) + - Release gix-date v0.7.1, gix-hash v0.11.4, gix-trace v0.1.3, gix-features v0.32.0, gix-actor v0.24.0, gix-validate v0.7.7, gix-object v0.33.0, gix-path v0.8.4, gix-glob v0.10.0, gix-quote v0.4.6, gix-attributes v0.15.0, gix-command v0.2.7, gix-packetline-blocking v0.16.3, gix-filter v0.1.0, gix-fs v0.4.0, gix-chunk v0.4.4, gix-commitgraph v0.18.0, gix-hashtable v0.2.4, gix-revwalk v0.4.0, gix-traverse v0.30.0, gix-worktree-stream v0.2.0, gix-archive v0.2.0, gix-config-value v0.12.4, gix-tempfile v7.0.1, gix-utils v0.1.5, gix-lock v7.0.2, gix-ref v0.33.0, gix-sec v0.8.4, gix-prompt v0.5.3, gix-url v0.21.0, gix-credentials v0.17.0, gix-diff v0.33.0, gix-discover v0.22.0, gix-ignore v0.5.0, gix-bitmap v0.2.6, gix-index v0.21.0, gix-mailmap v0.16.0, gix-negotiate v0.5.0, gix-pack v0.40.0, gix-odb v0.50.0, gix-packetline v0.16.4, gix-transport v0.34.0, gix-protocol v0.36.0, gix-revision v0.18.0, gix-refspec v0.14.0, gix-worktree v0.22.0, gix v0.49.1 ([`5cb3589`](https://github.com/Byron/gitoxide/commit/5cb3589b74fc5376e02cbfe151e71344e1c417fe)) + - Merge branch 'improvements-for-crates-index' ([`7734736`](https://github.com/Byron/gitoxide/commit/7734736ce7e590b2ad60f3c1d8289854931d155c)) + - `TreeRef::bisect_entry()` to correctly find an entry by name ([`424d347`](https://github.com/Byron/gitoxide/commit/424d347bb2466ecdf8cfc9e0da779d604d1f9e4e)) + - Update changelogs prior to release ([`2fc66b5`](https://github.com/Byron/gitoxide/commit/2fc66b55097ed494b72d1af939ba5561f71fde97)) + - Merge branch 'improvements-for-crates-index' ([`3f914e8`](https://github.com/Byron/gitoxide/commit/3f914e8840afc59441c3c463bdc89c53136d583e)) + - `Copy` for `tree::EntryRef` ([`437fedc`](https://github.com/Byron/gitoxide/commit/437fedc59c2bad57beb3cf54e4c71a470bd22ee2)) + - Update license field following SPDX 2.1 license expression standard ([`9064ea3`](https://github.com/Byron/gitoxide/commit/9064ea31fae4dc59a56bdd3a06c0ddc990ee689e)) +</details> + +## 0.33.0 (2023-07-19) + +### New Features + + - <csr-id-695de5679904776798b4d8b9dbee771306ff39ba/> Add classifier methods to `Kind` for easier object classification. + This allows to avoid having to think about where to right type lives + for comparisons or matches in simple cases that are about one specific object type. + - <csr-id-437fedc59c2bad57beb3cf54e4c71a470bd22ee2/> `Copy` for `tree::EntryRef` + - <csr-id-424d347bb2466ecdf8cfc9e0da779d604d1f9e4e/> `TreeRef::bisect_entry()` to correctly find an entry by name + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 5 commits contributed to the release. + - 19 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-features v0.32.0, gix-actor v0.24.0, gix-glob v0.10.0, gix-attributes v0.15.0, gix-commitgraph v0.18.0, gix-config-value v0.12.4, gix-fs v0.4.0, gix-object v0.33.0, gix-ref v0.33.0, gix-config v0.26.0, gix-command v0.2.7, gix-url v0.21.0, gix-credentials v0.17.0, gix-diff v0.33.0, gix-discover v0.22.0, gix-filter v0.1.0, gix-ignore v0.5.0, gix-revwalk v0.4.0, gix-traverse v0.30.0, gix-index v0.21.0, gix-mailmap v0.16.0, gix-negotiate v0.5.0, gix-pack v0.40.0, gix-odb v0.50.0, gix-transport v0.34.0, gix-protocol v0.36.0, gix-revision v0.18.0, gix-refspec v0.14.0, gix-worktree v0.22.0, gix v0.49.0 ([`68ae3ff`](https://github.com/Byron/gitoxide/commit/68ae3ff9d642ec56f088a6a682a073dc16f4e8ca)) + - Adjust package versions (by cargo-smart-release) ([`c70e54f`](https://github.com/Byron/gitoxide/commit/c70e54f163c312c87753a506eeaad462e8579bfb)) + - Prepare changelogs prior to release ([`e4dded0`](https://github.com/Byron/gitoxide/commit/e4dded05138562f9737a7dcfb60570c55769486d)) + - Merge branch 'adjustments-for-crates-index' ([`b82868d`](https://github.com/Byron/gitoxide/commit/b82868d5688d8d4849c47ed3d209a96ee59e69b3)) + - Add classifier methods to `Kind` for easier object classification. ([`695de56`](https://github.com/Byron/gitoxide/commit/695de5679904776798b4d8b9dbee771306ff39ba)) +</details> + +## 0.32.0 (2023-06-29) + +A maintenance release without user-facing changes. + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 4 commits contributed to the release. + - 6 days passed between releases. + - 0 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-date v0.7.0, gix-trace v0.1.2, gix-actor v0.23.0, gix-commitgraph v0.17.1, gix-utils v0.1.4, gix-object v0.32.0, gix-ref v0.32.0, gix-config v0.25.0, gix-diff v0.32.0, gix-discover v0.21.0, gix-hashtable v0.2.3, gix-revwalk v0.3.0, gix-traverse v0.29.0, gix-index v0.20.0, gix-mailmap v0.15.0, gix-negotiate v0.4.0, gix-pack v0.39.0, gix-odb v0.49.0, gix-protocol v0.35.0, gix-revision v0.17.0, gix-refspec v0.13.0, gix-worktree v0.21.0, gix v0.48.0, safety bump 20 crates ([`27e8c18`](https://github.com/Byron/gitoxide/commit/27e8c18db5a9a21843381c116a8ed6d9f681b3f8)) + - Prepare changelogs prior to release ([`00f96fb`](https://github.com/Byron/gitoxide/commit/00f96fb3110a8f81a1bd0d74c757c15b8773c6f6)) + - Merge branch 'i64-times' ([`b407461`](https://github.com/Byron/gitoxide/commit/b407461d8991db67a5bdb2ab13f518f78a85ed40)) + - Add a test to see what happens if negative dates are used in commits ([`57a5cd1`](https://github.com/Byron/gitoxide/commit/57a5cd1ca2f8153568c366cd1709be7d4ebec972)) +</details> + +## 0.31.0 (2023-06-22) + +<csr-id-bcad5c22049d56a25ef69d6c7a3344e78f9a1d4d/> + +### Chore + + - <csr-id-bcad5c22049d56a25ef69d6c7a3344e78f9a1d4d/> Add `clippy::redundant-closure-for-method-calls` lint + +### Commit Statistics + +<csr-read-only-do-not-edit/> + + - 10 commits contributed to the release over the course of 11 calendar days. + - 15 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.6.0, gix-hash v0.11.3, gix-trace v0.1.1, gix-features v0.31.0, gix-actor v0.22.0, gix-path v0.8.2, gix-glob v0.9.0, gix-quote v0.4.5, gix-attributes v0.14.0, gix-chunk v0.4.3, gix-commitgraph v0.17.0, gix-config-value v0.12.2, gix-fs v0.3.0, gix-tempfile v7.0.0, gix-utils v0.1.3, gix-lock v7.0.0, gix-validate v0.7.6, gix-object v0.31.0, gix-ref v0.31.0, gix-sec v0.8.2, gix-config v0.24.0, gix-command v0.2.6, gix-prompt v0.5.2, gix-url v0.20.0, gix-credentials v0.16.0, gix-diff v0.31.0, gix-discover v0.20.0, gix-hashtable v0.2.2, gix-ignore v0.4.0, gix-bitmap v0.2.5, gix-revwalk v0.2.0, gix-traverse v0.28.0, gix-index v0.19.0, gix-mailmap v0.14.0, gix-negotiate v0.3.0, gix-pack v0.38.0, gix-odb v0.48.0, gix-packetline v0.16.3, gix-transport v0.33.0, gix-protocol v0.34.0, gix-revision v0.16.0, gix-refspec v0.12.0, gix-worktree v0.20.0, gix v0.47.0, gitoxide-core v0.29.0, gitoxide v0.27.0, safety bump 30 crates ([`ea9f942`](https://github.com/Byron/gitoxide/commit/ea9f9424e777f10da0e33bb9ffbbefd01c4c5a74)) + - Prepare changelogs prior to release ([`18b0a37`](https://github.com/Byron/gitoxide/commit/18b0a371941aa2d4d62512437d5daa351ba99ffd)) + - `just fmt` ([`871dd0b`](https://github.com/Byron/gitoxide/commit/871dd0b977caf17159092a4739ba5408403cdb2c)) + - Merge branch 'corpus' ([`aa16c8c`](https://github.com/Byron/gitoxide/commit/aa16c8ce91452a3e3063cf1cf0240b6014c4743f)) + - Change MSRV to 1.65 ([`4f635fc`](https://github.com/Byron/gitoxide/commit/4f635fc4429350bae2582d25de86429969d28f30)) + - Merge branch 'help-874-redundant-closures' ([`fe59956`](https://github.com/Byron/gitoxide/commit/fe59956ad667303a923d7cfd9ffd72283df41d78)) + - Add `clippy::redundant-closure-for-method-calls` lint ([`bcad5c2`](https://github.com/Byron/gitoxide/commit/bcad5c22049d56a25ef69d6c7a3344e78f9a1d4d)) + - Merge branch 'future-dates' ([`8d2e6a9`](https://github.com/Byron/gitoxide/commit/8d2e6a91ac92a033e9e3daad5cffa90263075536)) + - Adapt to changes in `gix-actor` ([`4a80e86`](https://github.com/Byron/gitoxide/commit/4a80e868f9530896616e649838e9be64b6d10036)) + - Adapt to changes in `gix-date` ([`d575336`](https://github.com/Byron/gitoxide/commit/d575336c26e6026e463cd06d88266bb2bdd3e162)) +</details> + ## 0.30.0 (2023-06-06) A maintenance release without user-facing changes. @@ -13,7 +316,7 @@ A maintenance release without user-facing changes. <csr-read-only-do-not-edit/> - - 14 commits contributed to the release over the course of 12 calendar days. + - 15 commits contributed to the release over the course of 12 calendar days. - 25 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -25,6 +328,7 @@ A maintenance release without user-facing changes. <details><summary>view details</summary> * **Uncategorized** + - Release gix-date v0.5.1, gix-hash v0.11.2, gix-features v0.30.0, gix-actor v0.21.0, gix-path v0.8.1, gix-glob v0.8.0, gix-quote v0.4.4, gix-attributes v0.13.0, gix-chunk v0.4.2, gix-commitgraph v0.16.0, gix-config-value v0.12.1, gix-fs v0.2.0, gix-tempfile v6.0.0, gix-utils v0.1.2, gix-lock v6.0.0, gix-validate v0.7.5, gix-object v0.30.0, gix-ref v0.30.0, gix-sec v0.8.1, gix-config v0.23.0, gix-command v0.2.5, gix-prompt v0.5.1, gix-url v0.19.0, gix-credentials v0.15.0, gix-diff v0.30.0, gix-discover v0.19.0, gix-hashtable v0.2.1, gix-ignore v0.3.0, gix-bitmap v0.2.4, gix-traverse v0.26.0, gix-index v0.17.0, gix-mailmap v0.13.0, gix-revision v0.15.0, gix-negotiate v0.2.0, gix-pack v0.36.0, gix-odb v0.46.0, gix-packetline v0.16.2, gix-transport v0.32.0, gix-protocol v0.33.0, gix-refspec v0.11.0, gix-worktree v0.18.0, gix v0.45.0, safety bump 29 crates ([`9a9fa96`](https://github.com/Byron/gitoxide/commit/9a9fa96fa8a722bddc5c3b2270b0edf8f6615141)) - `just fmt` ([`ffc1276`](https://github.com/Byron/gitoxide/commit/ffc1276e0c991ac33ce842f5dca0b45ac69680c0)) - Prepare changelogs prior to release ([`8f15cec`](https://github.com/Byron/gitoxide/commit/8f15cec1ec7d5a9d56bb158f155011ef2bb3539b)) - Merge pull request #878 from blinxen/main ([`67da689`](https://github.com/Byron/gitoxide/commit/67da6894c8d8a24b982c732a1753a3e0a3300cc3)) diff --git a/vendor/gix-object/Cargo.toml b/vendor/gix-object/Cargo.toml index 36f027216..2d1142e20 100644 --- a/vendor/gix-object/Cargo.toml +++ b/vendor/gix-object/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.64" +rust-version = "1.65" name = "gix-object" -version = "0.30.0" +version = "0.37.0" authors = ["Sebastian Thiel <sebastian.thiel@icloud.com>"] include = [ "src/**/*", @@ -21,7 +21,7 @@ include = [ "CHANGELOG.md", ] description = "Immutable and mutable git objects with decoding and encoding support" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/Byron/gitoxide" [package.metadata.docs.rs] @@ -35,6 +35,11 @@ rustdoc-args = [ [lib] doctest = false +[[bench]] +name = "decode-objects" +path = "./benches/decode_objects.rs" +harness = false + [dependencies.bstr] version = "1.3.0" features = [ @@ -51,29 +56,24 @@ version = "0.2.0" optional = true [dependencies.gix-actor] -version = "^0.21.0" +version = "^0.27.0" + +[dependencies.gix-date] +version = "^0.8.0" [dependencies.gix-features] -version = "^0.30.0" +version = "^0.35.0" features = ["rustsha1"] [dependencies.gix-hash] -version = "^0.11.2" +version = "^0.13.0" [dependencies.gix-validate] -version = "^0.7.5" - -[dependencies.hex] -version = "0.4.2" +version = "^0.8.0" [dependencies.itoa] version = "1.0.1" -[dependencies.nom] -version = "7" -features = ["std"] -default-features = false - [dependencies.serde] version = "1.0.114" features = ["derive"] @@ -87,6 +87,13 @@ features = ["write"] [dependencies.thiserror] version = "1.0.34" +[dependencies.winnow] +version = "0.5.14" +features = ["simd"] + +[dev-dependencies.criterion] +version = "0.5.1" + [dev-dependencies.pretty_assertions] version = "1.0.0" @@ -98,4 +105,4 @@ serde = [ "gix-hash/serde", "gix-actor/serde", ] -verbose-object-parsing-errors = ["nom/std"] +verbose-object-parsing-errors = [] diff --git a/vendor/gix-object/src/blob.rs b/vendor/gix-object/src/blob.rs index ff2eeafc8..d0a42092c 100644 --- a/vendor/gix-object/src/blob.rs +++ b/vendor/gix-object/src/blob.rs @@ -4,32 +4,32 @@ use crate::{Blob, BlobRef, Kind}; impl<'a> crate::WriteTo for BlobRef<'a> { /// Write the blobs data to `out` verbatim. - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { out.write_all(self.data) } - fn size(&self) -> usize { - self.data.len() - } - fn kind(&self) -> Kind { Kind::Blob } + + fn size(&self) -> usize { + self.data.len() + } } impl crate::WriteTo for Blob { /// Write the blobs data to `out` verbatim. - fn write_to(&self, out: impl io::Write) -> io::Result<()> { + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { self.to_ref().write_to(out) } - fn size(&self) -> usize { - self.to_ref().size() - } - fn kind(&self) -> Kind { Kind::Blob } + + fn size(&self) -> usize { + self.to_ref().size() + } } impl Blob { diff --git a/vendor/gix-object/src/commit/decode.rs b/vendor/gix-object/src/commit/decode.rs index 821feaabb..0b8243ef3 100644 --- a/vendor/gix-object/src/commit/decode.rs +++ b/vendor/gix-object/src/commit/decode.rs @@ -1,71 +1,71 @@ use std::borrow::Cow; -use nom::{ - branch::alt, - bytes::complete::{is_not, tag}, - combinator::{all_consuming, opt}, - error::{context, ContextError, ParseError}, - multi::many0, - IResult, Parser, -}; use smallvec::SmallVec; +use winnow::{ + combinator::{alt, eof, opt, preceded, repeat, rest, terminated}, + error::{AddContext, ParserError, StrContext}, + prelude::*, + token::take_till1, +}; use crate::{parse, parse::NL, BStr, ByteSlice, CommitRef}; -pub fn message<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], &'a BStr, E> { +pub fn message<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>( + i: &mut &'a [u8], +) -> PResult<&'a BStr, E> { if i.is_empty() { // newline + [message] - return Err(nom::Err::Error(E::add_context( - i, - "newline + <message>", - E::from_error_kind(i, nom::error::ErrorKind::Eof), - ))); + return Err( + winnow::error::ErrMode::from_error_kind(i, winnow::error::ErrorKind::Eof) + .add_context(i, StrContext::Expected("newline + <message>".into())), + ); } - let (i, _) = context("a newline separates headers from the message", tag(NL))(i)?; - Ok((&[], i.as_bstr())) + preceded(NL, rest.map(ByteSlice::as_bstr)) + .context(StrContext::Expected( + "a newline separates headers from the message".into(), + )) + .parse_next(i) } -pub fn commit<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( - i: &'a [u8], -) -> IResult<&'a [u8], CommitRef<'_>, E> { - let (i, tree) = context("tree <40 lowercase hex char>", |i| { - parse::header_field(i, b"tree", parse::hex_hash) - })(i)?; - let (i, parents) = context( - "zero or more 'parent <40 lowercase hex char>'", - many0(|i| parse::header_field(i, b"parent", parse::hex_hash)), - )(i)?; - let (i, author) = context("author <signature>", |i| { - parse::header_field(i, b"author", parse::signature) - })(i)?; - let (i, committer) = context("committer <signature>", |i| { - parse::header_field(i, b"committer", parse::signature) - })(i)?; - let (i, encoding) = context( - "encoding <encoding>", - opt(|i| parse::header_field(i, b"encoding", is_not(NL))), - )(i)?; - let (i, extra_headers) = context( - "<field> <single-line|multi-line>", - many0(alt(( - parse::any_header_field_multi_line.map(|(k, o)| (k.as_bstr(), Cow::Owned(o))), - |i| { - parse::any_header_field(i, is_not(NL)).map(|(i, (k, o))| (i, (k.as_bstr(), Cow::Borrowed(o.as_bstr())))) +pub fn commit<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>( + i: &mut &'a [u8], +) -> PResult<CommitRef<'a>, E> { + ( + (|i: &mut _| parse::header_field(i, b"tree", parse::hex_hash)) + .context(StrContext::Expected("tree <40 lowercase hex char>".into())), + repeat(0.., |i: &mut _| parse::header_field(i, b"parent", parse::hex_hash)) + .map(|p: Vec<_>| p) + .context(StrContext::Expected( + "zero or more 'parent <40 lowercase hex char>'".into(), + )), + (|i: &mut _| parse::header_field(i, b"author", parse::signature)) + .context(StrContext::Expected("author <signature>".into())), + (|i: &mut _| parse::header_field(i, b"committer", parse::signature)) + .context(StrContext::Expected("committer <signature>".into())), + opt(|i: &mut _| parse::header_field(i, b"encoding", take_till1(NL))) + .context(StrContext::Expected("encoding <encoding>".into())), + repeat( + 0.., + alt(( + parse::any_header_field_multi_line.map(|(k, o)| (k.as_bstr(), Cow::Owned(o))), + |i: &mut _| { + parse::any_header_field(i, take_till1(NL)).map(|(k, o)| (k.as_bstr(), Cow::Borrowed(o.as_bstr()))) + }, + )), + ) + .context(StrContext::Expected("<field> <single-line|multi-line>".into())), + terminated(message, eof), + ) + .map( + |(tree, parents, author, committer, encoding, extra_headers, message)| CommitRef { + tree, + parents: SmallVec::from(parents), + author, + committer, + encoding: encoding.map(ByteSlice::as_bstr), + message, + extra_headers, }, - ))), - )(i)?; - let (i, message) = all_consuming(message)(i)?; - - Ok(( - i, - CommitRef { - tree, - parents: SmallVec::from(parents), - author, - committer, - encoding: encoding.map(ByteSlice::as_bstr), - message, - extra_headers, - }, - )) + ) + .parse_next(i) } diff --git a/vendor/gix-object/src/commit/message/body.rs b/vendor/gix-object/src/commit/message/body.rs index 855f031be..6301bf30e 100644 --- a/vendor/gix-object/src/commit/message/body.rs +++ b/vendor/gix-object/src/commit/message/body.rs @@ -1,11 +1,10 @@ use std::ops::Deref; -use nom::{ - bytes::complete::{tag, take_until1}, - combinator::all_consuming, - error::{ErrorKind, ParseError}, - sequence::terminated, - IResult, +use winnow::{ + combinator::{eof, rest, separated_pair, terminated}, + error::{ErrorKind, ParserError}, + prelude::*, + token::take_until1, }; use crate::{ @@ -32,12 +31,14 @@ pub struct TrailerRef<'a> { pub value: &'a BStr, } -fn parse_single_line_trailer<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], (&'a BStr, &'a BStr), E> { - let (value, token) = terminated(take_until1(b":".as_ref()), tag(b": "))(i.trim_end())?; +fn parse_single_line_trailer<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<(&'a BStr, &'a BStr), E> { + *i = i.trim_end(); + let (token, value) = separated_pair(take_until1(b":".as_ref()), b": ", rest).parse_next(i)?; + if token.trim_end().len() != token.len() || value.trim_start().len() != value.len() { - Err(nom::Err::Failure(E::from_error_kind(i, ErrorKind::Fail))) + Err(winnow::error::ErrMode::from_error_kind(i, ErrorKind::Fail).cut()) } else { - Ok((&[], (token.as_bstr(), value.as_bstr()))) + Ok((token.as_bstr(), value.as_bstr())) } } @@ -48,15 +49,15 @@ impl<'a> Iterator for Trailers<'a> { if self.cursor.is_empty() { return None; } - for line in self.cursor.lines_with_terminator() { + for mut line in self.cursor.lines_with_terminator() { self.cursor = &self.cursor[line.len()..]; - if let Some(trailer) = - all_consuming(parse_single_line_trailer::<()>)(line) - .ok() - .map(|(_, (token, value))| TrailerRef { - token: token.trim().as_bstr(), - value: value.trim().as_bstr(), - }) + if let Some(trailer) = terminated(parse_single_line_trailer::<()>, eof) + .parse_next(&mut line) + .ok() + .map(|(token, value)| TrailerRef { + token: token.trim().as_bstr(), + value: value.trim().as_bstr(), + }) { return Some(trailer); } @@ -118,7 +119,7 @@ mod test_parse_trailer { use super::*; fn parse(input: &str) -> (&BStr, &BStr) { - parse_single_line_trailer::<()>(input.as_bytes()).unwrap().1 + parse_single_line_trailer::<()>.parse_peek(input.as_bytes()).unwrap().1 } #[test] @@ -141,8 +142,8 @@ mod test_parse_trailer { #[test] fn extra_whitespace_before_token_or_value_is_error() { - assert!(parse_single_line_trailer::<()>(b"foo : bar").is_err()); - assert!(parse_single_line_trailer::<()>(b"foo: bar").is_err()) + assert!(parse_single_line_trailer::<()>.parse_peek(b"foo : bar").is_err()); + assert!(parse_single_line_trailer::<()>.parse_peek(b"foo: bar").is_err()) } #[test] diff --git a/vendor/gix-object/src/commit/message/decode.rs b/vendor/gix-object/src/commit/message/decode.rs index 6224909bd..8038009b4 100644 --- a/vendor/gix-object/src/commit/message/decode.rs +++ b/vendor/gix-object/src/commit/message/decode.rs @@ -1,57 +1,49 @@ -use nom::{ - branch::alt, - bytes::complete::{tag, take_till1}, - combinator::all_consuming, - error::ParseError, - sequence::pair, - IResult, +use winnow::{ + combinator::{alt, eof, preceded, rest, terminated}, + error::ParserError, + prelude::*, + stream::{Offset, Stream}, + token::take_till1, }; use crate::bstr::{BStr, ByteSlice}; -pub(crate) fn newline<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], &'a [u8], E> { - alt((tag(b"\r\n"), tag(b"\n")))(i) +pub(crate) fn newline<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<&'a [u8], E> { + alt((b"\n", b"\r\n")).parse_next(i) } -fn subject_and_body<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], (&'a BStr, Option<&'a BStr>), E> { - let mut c = i; - let mut consumed_bytes = 0; - while !c.is_empty() { - c = match take_till1::<_, _, E>(|c| c == b'\n' || c == b'\r')(c) { - Ok((i1, segment)) => { - consumed_bytes += segment.len(); - match pair::<_, _, _, E, _, _>(newline, newline)(i1) { - Ok((body, _)) => { - return Ok(( - &[], - ( - i[0usize..consumed_bytes].as_bstr(), - (!body.is_empty()).then(|| body.as_bstr()), - ), - )); +fn subject_and_body<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<(&'a BStr, Option<&'a BStr>), E> { + let start_i = *i; + let start = i.checkpoint(); + while !i.is_empty() { + match take_till1::<_, _, E>(|c| c == b'\n' || c == b'\r').parse_next(i) { + Ok(_) => { + let consumed_bytes = i.offset_from(&start); + match preceded((newline::<E>, newline::<E>), rest).parse_next(i) { + Ok(body) => { + let body = (!body.is_empty()).then(|| body.as_bstr()); + return Ok((start_i[0usize..consumed_bytes].as_bstr(), body)); } - Err(_) => match i1.get(1..) { - Some(next) => { - consumed_bytes += 1; - next - } + Err(_) => match i.next_token() { + Some(_) => {} None => break, }, } } - Err(_) => match c.get(1..) { - Some(next) => { - consumed_bytes += 1; - next - } + Err(_) => match i.next_token() { + Some(_) => {} None => break, }, - }; + } } - Ok((&[], (i.as_bstr(), None))) + + i.reset(start); + rest.map(|r: &[u8]| (r.as_bstr(), None)).parse_next(i) } /// Returns title and body, without separator -pub fn message(input: &[u8]) -> (&BStr, Option<&BStr>) { - all_consuming(subject_and_body::<()>)(input).expect("cannot fail").1 +pub fn message(mut input: &[u8]) -> (&BStr, Option<&BStr>) { + terminated(subject_and_body::<()>, eof) + .parse_next(&mut input) + .expect("cannot fail") } diff --git a/vendor/gix-object/src/commit/mod.rs b/vendor/gix-object/src/commit/mod.rs index 9e135df28..b3de9b0a4 100644 --- a/vendor/gix-object/src/commit/mod.rs +++ b/vendor/gix-object/src/commit/mod.rs @@ -1,4 +1,6 @@ -use bstr::{BStr, ByteSlice}; +use std::ops::Range; + +use bstr::{BStr, BString, ByteSlice}; use crate::{Commit, CommitRef, TagRef}; @@ -21,16 +23,49 @@ pub struct MessageRef<'a> { pub body: Option<&'a BStr>, } +/// The raw commit data, parseable by [`CommitRef`] or [`Commit`], which was fed into a program to produce a signature. +/// +/// See [`extract_signature()`](crate::CommitRefIter::signature()) for how to obtain it. +// TODO: implement `std::io::Read` to avoid allocations +#[derive(PartialEq, Eq, Debug, Hash, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SignedData<'a> { + /// The raw commit data that includes the signature. + data: &'a [u8], + /// The byte range at which we find the signature. All but the signature is the data that was signed. + signature_range: Range<usize>, +} + +impl SignedData<'_> { + /// Convenience method to obtain a copy of the signed data. + pub fn to_bstring(&self) -> BString { + let mut buf = BString::from(&self.data[..self.signature_range.start]); + buf.extend_from_slice(&self.data[self.signature_range.end..]); + buf + } +} + +impl From<SignedData<'_>> for BString { + fn from(value: SignedData<'_>) -> Self { + value.to_bstring() + } +} + /// pub mod ref_iter; mod write; +/// Lifecycle impl<'a> CommitRef<'a> { /// Deserialize a commit from the given `data` bytes while avoiding most allocations. - pub fn from_bytes(data: &'a [u8]) -> Result<CommitRef<'a>, crate::decode::Error> { - decode::commit(data).map(|(_, t)| t).map_err(crate::decode::Error::from) + pub fn from_bytes(mut data: &'a [u8]) -> Result<CommitRef<'a>, crate::decode::Error> { + decode::commit(&mut data).map_err(crate::decode::Error::with_err) } +} + +/// Access +impl<'a> CommitRef<'a> { /// Return the `tree` fields hash digest. pub fn tree(&self) -> gix_hash::ObjectId { gix_hash::ObjectId::from_hex(self.tree).expect("prior validation of tree hash during parsing") @@ -45,7 +80,7 @@ impl<'a> CommitRef<'a> { /// Returns a convenient iterator over all extra headers. pub fn extra_headers(&self) -> crate::commit::ExtraHeaders<impl Iterator<Item = (&BStr, &BStr)>> { - crate::commit::ExtraHeaders::new(self.extra_headers.iter().map(|(k, v)| (*k, v.as_ref()))) + ExtraHeaders::new(self.extra_headers.iter().map(|(k, v)| (*k, v.as_ref()))) } /// Return the author, with whitespace trimmed. @@ -68,7 +103,7 @@ impl<'a> CommitRef<'a> { } /// Returns the time at which this commit was created. - pub fn time(&self) -> gix_actor::Time { + pub fn time(&self) -> gix_date::Time { self.committer.time } } diff --git a/vendor/gix-object/src/commit/ref_iter.rs b/vendor/gix-object/src/commit/ref_iter.rs index 454f69ac0..4401384ca 100644 --- a/vendor/gix-object/src/commit/ref_iter.rs +++ b/vendor/gix-object/src/commit/ref_iter.rs @@ -1,15 +1,21 @@ -use std::borrow::Cow; +use std::{borrow::Cow, ops::Range}; use bstr::BStr; use gix_hash::{oid, ObjectId}; -use nom::{ - branch::alt, - bytes::complete::is_not, - combinator::{all_consuming, opt}, - error::context, +use winnow::{ + combinator::{alt, eof, opt, terminated}, + error::StrContext, + prelude::*, + token::take_till1, }; -use crate::{bstr::ByteSlice, commit::decode, parse, parse::NL, CommitRefIter}; +use crate::{ + bstr::ByteSlice, + commit::{decode, SignedData}, + parse, + parse::NL, + CommitRefIter, +}; #[derive(Copy, Clone)] pub(crate) enum SignatureKind { @@ -30,6 +36,7 @@ pub(crate) enum State { Message, } +/// Lifecycle impl<'a> CommitRefIter<'a> { /// Create a commit iterator from data. pub fn from_bytes(data: &'a [u8]) -> CommitRefIter<'a> { @@ -38,6 +45,37 @@ impl<'a> CommitRefIter<'a> { state: State::default(), } } +} + +/// Access +impl<'a> CommitRefIter<'a> { + /// Parse `data` as commit and return its PGP signature, along with *all non-signature* data as [`SignedData`], or `None` + /// if the commit isn't signed. + /// + /// This allows the caller to validate the signature by passing the signed data along with the signature back to the program + /// that created it. + pub fn signature(data: &'a [u8]) -> Result<Option<(Cow<'a, BStr>, SignedData<'a>)>, crate::decode::Error> { + let mut signature_and_range = None; + + let raw_tokens = CommitRefIterRaw { + data, + state: State::default(), + offset: 0, + }; + for token in raw_tokens { + let token = token?; + if let Token::ExtraHeader((name, value)) = &token.token { + if *name == "gpgsig" { + // keep track of the signature range alongside the signature data, + // because all but the signature is the signed data. + signature_and_range = Some((value.clone(), token.token_range)); + break; + } + } + } + + Ok(signature_and_range.map(|(sig, signature_range)| (sig, SignedData { data, signature_range }))) + } /// Returns the object id of this commits tree if it is the first function called and if there is no error in decoding /// the data. @@ -106,7 +144,7 @@ impl<'a> CommitRefIter<'a> { _ => None, }) .transpose() - .map(|msg| msg.unwrap_or_default()) + .map(Option::unwrap_or_default) } } @@ -115,13 +153,21 @@ fn missing_field() -> crate::decode::Error { } impl<'a> CommitRefIter<'a> { + #[inline] fn next_inner(i: &'a [u8], state: &mut State) -> Result<(&'a [u8], Token<'a>), crate::decode::Error> { + Self::next_inner_(i, state).map_err(crate::decode::Error::with_err) + } + + fn next_inner_( + mut i: &'a [u8], + state: &mut State, + ) -> Result<(&'a [u8], Token<'a>), winnow::error::ErrMode<crate::decode::ParseError>> { use State::*; Ok(match state { Tree => { - let (i, tree) = context("tree <40 lowercase hex char>", |i| { - parse::header_field(i, b"tree", parse::hex_hash) - })(i)?; + let tree = (|i: &mut _| parse::header_field(i, b"tree", parse::hex_hash)) + .context(StrContext::Expected("tree <40 lowercase hex char>".into())) + .parse_next(&mut i)?; *state = State::Parents; ( i, @@ -131,10 +177,9 @@ impl<'a> CommitRefIter<'a> { ) } Parents => { - let (i, parent) = context( - "commit <40 lowercase hex char>", - opt(|i| parse::header_field(i, b"parent", parse::hex_hash)), - )(i)?; + let parent = opt(|i: &mut _| parse::header_field(i, b"parent", parse::hex_hash)) + .context(StrContext::Expected("commit <40 lowercase hex char>".into())) + .parse_next(&mut i)?; match parent { Some(parent) => ( i, @@ -146,7 +191,7 @@ impl<'a> CommitRefIter<'a> { *state = State::Signature { of: SignatureKind::Author, }; - return Self::next_inner(i, state); + return Self::next_inner_(i, state); } } } @@ -162,7 +207,9 @@ impl<'a> CommitRefIter<'a> { (&b"committer"[..], "committer <signature>") } }; - let (i, signature) = context(err_msg, |i| parse::header_field(i, field_name, parse::signature))(i)?; + let signature = (|i: &mut _| parse::header_field(i, field_name, parse::signature)) + .context(StrContext::Expected(err_msg.into())) + .parse_next(&mut i)?; ( i, match who { @@ -172,37 +219,35 @@ impl<'a> CommitRefIter<'a> { ) } Encoding => { - let (i, encoding) = context( - "encoding <encoding>", - opt(|i| parse::header_field(i, b"encoding", is_not(NL))), - )(i)?; + let encoding = opt(|i: &mut _| parse::header_field(i, b"encoding", take_till1(NL))) + .context(StrContext::Expected("encoding <encoding>".into())) + .parse_next(&mut i)?; *state = State::ExtraHeaders; match encoding { Some(encoding) => (i, Token::Encoding(encoding.as_bstr())), - None => return Self::next_inner(i, state), + None => return Self::next_inner_(i, state), } } ExtraHeaders => { - let (i, extra_header) = context( - "<field> <single-line|multi-line>", - opt(alt(( - |i| parse::any_header_field_multi_line(i).map(|(i, (k, o))| (i, (k.as_bstr(), Cow::Owned(o)))), - |i| { - parse::any_header_field(i, is_not(NL)) - .map(|(i, (k, o))| (i, (k.as_bstr(), Cow::Borrowed(o.as_bstr())))) - }, - ))), - )(i)?; + let extra_header = opt(alt(( + |i: &mut _| parse::any_header_field_multi_line(i).map(|(k, o)| (k.as_bstr(), Cow::Owned(o))), + |i: &mut _| { + parse::any_header_field(i, take_till1(NL)) + .map(|(k, o)| (k.as_bstr(), Cow::Borrowed(o.as_bstr()))) + }, + ))) + .context(StrContext::Expected("<field> <single-line|multi-line>".into())) + .parse_next(&mut i)?; match extra_header { Some(extra_header) => (i, Token::ExtraHeader(extra_header)), None => { *state = State::Message; - return Self::next_inner(i, state); + return Self::next_inner_(i, state); } } } Message => { - let (i, message) = all_consuming(decode::message)(i)?; + let message = terminated(decode::message, eof).parse_next(&mut i)?; debug_assert!( i.is_empty(), "we should have consumed all data - otherwise iter may go forever" @@ -233,6 +278,48 @@ impl<'a> Iterator for CommitRefIter<'a> { } } +/// A variation of [`CommitRefIter`] that return's [`RawToken`]s instead. +struct CommitRefIterRaw<'a> { + data: &'a [u8], + state: State, + offset: usize, +} + +impl<'a> Iterator for CommitRefIterRaw<'a> { + type Item = Result<RawToken<'a>, crate::decode::Error>; + + fn next(&mut self) -> Option<Self::Item> { + if self.data.is_empty() { + return None; + } + match CommitRefIter::next_inner(self.data, &mut self.state) { + Ok((remaining, token)) => { + let consumed = self.data.len() - remaining.len(); + let start = self.offset; + let end = start + consumed; + self.offset = end; + + self.data = remaining; + Some(Ok(RawToken { + token, + token_range: start..end, + })) + } + Err(err) => { + self.data = &[]; + Some(Err(err)) + } + } + } +} + +/// A combination of a parsed [`Token`] as well as the range of bytes that were consumed to parse it. +struct RawToken<'a> { + /// The parsed token. + token: Token<'a>, + token_range: Range<usize>, +} + /// A token returned by the [commit iterator][CommitRefIter]. #[allow(missing_docs)] #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] diff --git a/vendor/gix-object/src/commit/write.rs b/vendor/gix-object/src/commit/write.rs index e498789a2..667d25763 100644 --- a/vendor/gix-object/src/commit/write.rs +++ b/vendor/gix-object/src/commit/write.rs @@ -6,7 +6,7 @@ use crate::{encode, encode::NL, Commit, CommitRef, Kind}; impl crate::WriteTo for Commit { /// Serializes this instance to `out` in the git serialization format. - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + fn write_to(&self, mut out: &mut dyn io::Write) -> io::Result<()> { encode::trusted_header_id(b"tree", &self.tree, &mut out)?; for parent in &self.parents { encode::trusted_header_id(b"parent", parent, &mut out)?; @@ -52,7 +52,7 @@ impl crate::WriteTo for Commit { impl<'a> crate::WriteTo for CommitRef<'a> { /// Serializes this instance to `out` in the git serialization format. - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + fn write_to(&self, mut out: &mut dyn io::Write) -> io::Result<()> { encode::trusted_header_id(b"tree", &self.tree(), &mut out)?; for parent in self.parents() { encode::trusted_header_id(b"parent", &parent, &mut out)?; diff --git a/vendor/gix-object/src/data.rs b/vendor/gix-object/src/data.rs index e66360357..cea807684 100644 --- a/vendor/gix-object/src/data.rs +++ b/vendor/gix-object/src/data.rs @@ -67,8 +67,7 @@ pub mod verify { /// Compute the checksum of `self` and compare it with the `desired` hash. /// If the hashes do not match, an [`Error`] is returned, containing the actual /// hash of `self`. - pub fn verify_checksum(&self, desired: impl AsRef<gix_hash::oid>) -> Result<(), Error> { - let desired = desired.as_ref(); + pub fn verify_checksum(&self, desired: &gix_hash::oid) -> Result<(), Error> { let actual_id = crate::compute_hash(desired.kind(), self.kind, self.data); if desired != actual_id { return Err(Error::ChecksumMismatch { @@ -87,6 +86,9 @@ mod tests { #[test] fn size_of_object() { + #[cfg(target_pointer_width = "64")] assert_eq!(std::mem::size_of::<Data<'_>>(), 24, "this shouldn't change unnoticed"); + #[cfg(target_pointer_width = "32")] + assert_eq!(std::mem::size_of::<Data<'_>>(), 12, "this shouldn't change unnoticed"); } } diff --git a/vendor/gix-object/src/encode.rs b/vendor/gix-object/src/encode.rs index 6d291c92a..3ba7db0b5 100644 --- a/vendor/gix-object/src/encode.rs +++ b/vendor/gix-object/src/encode.rs @@ -34,9 +34,9 @@ impl From<Error> for io::Error { } } -pub(crate) fn header_field_multi_line(name: &[u8], value: &[u8], mut out: impl io::Write) -> io::Result<()> { +pub(crate) fn header_field_multi_line(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> { let mut lines = value.as_bstr().split_str(b"\n"); - trusted_header_field(name, lines.next().ok_or(Error::EmptyValue)?, &mut out)?; + trusted_header_field(name, lines.next().ok_or(Error::EmptyValue)?, out)?; for line in lines { out.write_all(SPACE)?; out.write_all(line)?; @@ -45,7 +45,7 @@ pub(crate) fn header_field_multi_line(name: &[u8], value: &[u8], mut out: impl i Ok(()) } -pub(crate) fn trusted_header_field(name: &[u8], value: &[u8], mut out: impl io::Write) -> io::Result<()> { +pub(crate) fn trusted_header_field(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> { out.write_all(name)?; out.write_all(SPACE)?; out.write_all(value)?; @@ -55,22 +55,26 @@ pub(crate) fn trusted_header_field(name: &[u8], value: &[u8], mut out: impl io:: pub(crate) fn trusted_header_signature( name: &[u8], value: &gix_actor::SignatureRef<'_>, - mut out: impl io::Write, + out: &mut dyn io::Write, ) -> io::Result<()> { out.write_all(name)?; out.write_all(SPACE)?; - value.write_to(&mut out)?; + value.write_to(out)?; out.write_all(NL) } -pub(crate) fn trusted_header_id(name: &[u8], value: &gix_hash::ObjectId, mut out: impl io::Write) -> io::Result<()> { +pub(crate) fn trusted_header_id( + name: &[u8], + value: &gix_hash::ObjectId, + mut out: &mut dyn io::Write, +) -> io::Result<()> { out.write_all(name)?; out.write_all(SPACE)?; value.write_hex_to(&mut out)?; out.write_all(NL) } -pub(crate) fn header_field(name: &[u8], value: &[u8], out: impl io::Write) -> io::Result<()> { +pub(crate) fn header_field(name: &[u8], value: &[u8], out: &mut dyn io::Write) -> io::Result<()> { if value.is_empty() { return Err(Error::EmptyValue.into()); } diff --git a/vendor/gix-object/src/kind.rs b/vendor/gix-object/src/kind.rs index 86df251bf..93e457ca4 100644 --- a/vendor/gix-object/src/kind.rs +++ b/vendor/gix-object/src/kind.rs @@ -10,6 +10,7 @@ pub enum Error { InvalidObjectKind { kind: bstr::BString }, } +/// Initialization impl Kind { /// Parse a `Kind` from its serialized loose git objects. pub fn from_bytes(s: &[u8]) -> Result<Kind, Error> { @@ -21,7 +22,10 @@ impl Kind { _ => return Err(Error::InvalidObjectKind { kind: s.into() }), }) } +} +/// Access +impl Kind { /// Return the name of `self` for use in serialized loose git objects. pub fn as_bytes(&self) -> &[u8] { match self { @@ -31,6 +35,26 @@ impl Kind { Kind::Tag => b"tag", } } + + /// Returns `true` if this instance is representing a commit. + pub fn is_commit(&self) -> bool { + matches!(self, Kind::Commit) + } + + /// Returns `true` if this instance is representing a tree. + pub fn is_tree(&self) -> bool { + matches!(self, Kind::Tree) + } + + /// Returns `true` if this instance is representing a tag. + pub fn is_tag(&self) -> bool { + matches!(self, Kind::Tag) + } + + /// Returns `true` if this instance is representing a blob. + pub fn is_blob(&self) -> bool { + matches!(self, Kind::Blob) + } } impl fmt::Display for Kind { diff --git a/vendor/gix-object/src/lib.rs b/vendor/gix-object/src/lib.rs index d6c9fb760..56e0019fd 100644 --- a/vendor/gix-object/src/lib.rs +++ b/vendor/gix-object/src/lib.rs @@ -14,6 +14,8 @@ use std::borrow::Cow; /// For convenience to allow using `bstr` without adding it to own cargo manifest. pub use bstr; use bstr::{BStr, BString, ByteSlice}; +/// For convenience to allow using `gix-date` without adding it to own cargo manifest. +pub use gix_date as date; use smallvec::SmallVec; /// @@ -213,6 +215,8 @@ pub enum Object { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TreeRef<'a> { /// The directories and files contained in this tree. + /// + /// Beware that the sort order isn't *quite* by name, so one may bisect only with a [`tree::EntryRef`] to handle ordering correctly. #[cfg_attr(feature = "serde", serde(borrow))] pub entries: Vec<tree::EntryRef<'a>>, } @@ -229,6 +233,8 @@ pub struct TreeRefIter<'a> { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Tree { /// The directories and files contained in this tree. They must be and remain sorted by [`filename`][tree::Entry::filename]. + /// + /// Beware that the sort order isn't *quite* by name, so one may bisect only with a [`tree::Entry`] to handle ordering correctly. pub entries: Vec<tree::Entry>, } @@ -252,16 +258,12 @@ pub struct Data<'a> { pub mod decode { #[cfg(feature = "verbose-object-parsing-errors")] mod _decode { - use crate::bstr::{BString, ByteSlice}; - /// The type to be used for parse errors. - pub type ParseError<'a> = nom::error::VerboseError<&'a [u8]>; - /// The owned type to be used for parse errors. - pub type ParseErrorOwned = nom::error::VerboseError<BString>; + pub type ParseError = winnow::error::ContextError<winnow::error::StrContext>; pub(crate) fn empty_error() -> Error { Error { - inner: nom::error::VerboseError::<BString> { errors: Vec::new() }, + inner: winnow::error::ContextError::new(), } } @@ -269,22 +271,13 @@ pub mod decode { #[derive(Debug, Clone)] pub struct Error { /// The actual error - pub inner: ParseErrorOwned, + pub inner: ParseError, } - impl<'a> From<nom::Err<ParseError<'a>>> for Error { - fn from(v: nom::Err<ParseError<'a>>) -> Self { - Error { - inner: match v { - nom::Err::Error(err) | nom::Err::Failure(err) => nom::error::VerboseError { - errors: err - .errors - .into_iter() - .map(|(i, v)| (i.as_bstr().to_owned(), v)) - .collect(), - }, - nom::Err::Incomplete(_) => unreachable!("we don't have streaming parsers"), - }, + impl Error { + pub(crate) fn with_err(err: winnow::error::ErrMode<ParseError>) -> Self { + Self { + inner: err.into_inner().expect("we don't have streaming parsers"), } } } @@ -300,9 +293,7 @@ pub mod decode { #[cfg(not(feature = "verbose-object-parsing-errors"))] mod _decode { /// The type to be used for parse errors, discards everything and is zero size - pub type ParseError<'a> = (); - /// The owned type to be used for parse errors, discards everything and is zero size - pub type ParseErrorOwned = (); + pub type ParseError = (); pub(crate) fn empty_error() -> Error { Error { inner: () } @@ -312,16 +303,13 @@ pub mod decode { #[derive(Debug, Clone)] pub struct Error { /// The actual error - pub inner: ParseErrorOwned, + pub inner: ParseError, } - impl<'a> From<nom::Err<ParseError<'a>>> for Error { - fn from(v: nom::Err<ParseError<'a>>) -> Self { - Error { - inner: match v { - nom::Err::Error(err) | nom::Err::Failure(err) => err, - nom::Err::Incomplete(_) => unreachable!("we don't have streaming parsers"), - }, + impl Error { + pub(crate) fn with_err(err: winnow::error::ErrMode<ParseError>) -> Self { + Self { + inner: err.into_inner().expect("we don't have streaming parsers"), } } } @@ -333,7 +321,7 @@ pub mod decode { } } pub(crate) use _decode::empty_error; - pub use _decode::{Error, ParseError, ParseErrorOwned}; + pub use _decode::{Error, ParseError}; impl std::error::Error for Error {} /// Returned by [`loose_header()`] diff --git a/vendor/gix-object/src/object/mod.rs b/vendor/gix-object/src/object/mod.rs index c0f9dcd52..bebc1cc65 100644 --- a/vendor/gix-object/src/object/mod.rs +++ b/vendor/gix-object/src/object/mod.rs @@ -10,7 +10,7 @@ mod write { /// Serialization impl<'a> WriteTo for ObjectRef<'a> { /// Write the contained object to `out` in the git serialization format. - fn write_to(&self, out: impl io::Write) -> io::Result<()> { + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { use crate::ObjectRef::*; match self { Tree(v) => v.write_to(out), @@ -20,6 +20,10 @@ mod write { } } + fn kind(&self) -> Kind { + self.kind() + } + fn size(&self) -> usize { use crate::ObjectRef::*; match self { @@ -29,16 +33,12 @@ mod write { Tag(v) => v.size(), } } - - fn kind(&self) -> Kind { - self.kind() - } } /// Serialization impl WriteTo for Object { /// Write the contained object to `out` in the git serialization format. - fn write_to(&self, out: impl io::Write) -> io::Result<()> { + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { use crate::Object::*; match self { Tree(v) => v.write_to(out), @@ -48,6 +48,10 @@ mod write { } } + fn kind(&self) -> Kind { + self.kind() + } + fn size(&self) -> usize { use crate::Object::*; match self { @@ -57,10 +61,6 @@ mod write { Tag(v) => v.size(), } } - - fn kind(&self) -> Kind { - self.kind() - } } } diff --git a/vendor/gix-object/src/parse.rs b/vendor/gix-object/src/parse.rs index 20dd443c0..0013d9b72 100644 --- a/vendor/gix-object/src/parse.rs +++ b/vendor/gix-object/src/parse.rs @@ -1,11 +1,10 @@ use bstr::{BStr, BString, ByteVec}; -use nom::{ - bytes::complete::{is_not, tag, take_until, take_while_m_n}, - combinator::{peek, recognize}, - error::{context, ContextError, ParseError}, - multi::many1_count, - sequence::{preceded, terminated, tuple}, - IResult, +use winnow::{ + combinator::{preceded, repeat, terminated}, + error::{AddContext, ParserError, StrContext}, + prelude::*, + token::{take_till1, take_until0, take_while}, + Parser, }; use crate::ByteSlice; @@ -14,68 +13,63 @@ pub(crate) const NL: &[u8] = b"\n"; pub(crate) const SPACE: &[u8] = b" "; const SPACE_OR_NL: &[u8] = b" \n"; -pub(crate) fn any_header_field_multi_line<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( - i: &'a [u8], -) -> IResult<&'a [u8], (&'a [u8], BString), E> { - let (i, (k, o)) = context( - "name <multi-line-value>", - peek(tuple(( - terminated(is_not(SPACE_OR_NL), tag(SPACE)), - recognize(tuple(( - is_not(NL), - tag(NL), - many1_count(terminated(tuple((tag(SPACE), take_until(NL))), tag(NL))), - ))), - ))), - )(i)?; - assert!(!o.is_empty(), "we have parsed more than one value here"); - let end = &o[o.len() - 1] as *const u8 as usize; - let start_input = &i[0] as *const u8 as usize; - - let bytes = o[..o.len() - 1].as_bstr(); - let mut out = BString::from(Vec::with_capacity(bytes.len())); - let mut lines = bytes.lines(); - out.push_str(lines.next().expect("first line")); - for line in lines { - out.push(b'\n'); - out.push_str(&line[1..]); // cut leading space - } - Ok((&i[end - start_input + 1..], (k, out))) +pub(crate) fn any_header_field_multi_line<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>( + i: &mut &'a [u8], +) -> PResult<(&'a [u8], BString), E> { + ( + terminated(take_till1(SPACE_OR_NL), SPACE), + ( + take_till1(NL), + NL, + repeat(1.., terminated((SPACE, take_until0(NL)), NL)).map(|()| ()), + ) + .recognize() + .map(|o: &[u8]| { + let bytes = o.as_bstr(); + let mut out = BString::from(Vec::with_capacity(bytes.len())); + let mut lines = bytes.lines(); + out.push_str(lines.next().expect("first line")); + for line in lines { + out.push(b'\n'); + out.push_str(&line[1..]); // cut leading space + } + out + }), + ) + .context(StrContext::Expected("name <multi-line-value>".into())) + .parse_next(i) } -pub(crate) fn header_field<'a, T, E: ParseError<&'a [u8]>>( - i: &'a [u8], +pub(crate) fn header_field<'a, T, E: ParserError<&'a [u8]>>( + i: &mut &'a [u8], name: &'static [u8], - parse_value: impl Fn(&'a [u8]) -> IResult<&'a [u8], T, E>, -) -> IResult<&'a [u8], T, E> { - terminated(preceded(terminated(tag(name), tag(SPACE)), parse_value), tag(NL))(i) + parse_value: impl Parser<&'a [u8], T, E>, +) -> PResult<T, E> { + terminated(preceded(terminated(name, SPACE), parse_value), NL).parse_next(i) } -pub(crate) fn any_header_field<'a, T, E: ParseError<&'a [u8]>>( - i: &'a [u8], - parse_value: impl Fn(&'a [u8]) -> IResult<&'a [u8], T, E>, -) -> IResult<&'a [u8], (&'a [u8], T), E> { - terminated( - tuple((terminated(is_not(SPACE_OR_NL), tag(SPACE)), parse_value)), - tag(NL), - )(i) +pub(crate) fn any_header_field<'a, T, E: ParserError<&'a [u8]>>( + i: &mut &'a [u8], + parse_value: impl Parser<&'a [u8], T, E>, +) -> PResult<(&'a [u8], T), E> { + terminated((terminated(take_till1(SPACE_OR_NL), SPACE), parse_value), NL).parse_next(i) } fn is_hex_digit_lc(b: u8) -> bool { matches!(b, b'0'..=b'9' | b'a'..=b'f') } -pub fn hex_hash<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], &'a BStr, E> { - take_while_m_n( - gix_hash::Kind::shortest().len_in_hex(), - gix_hash::Kind::longest().len_in_hex(), +pub fn hex_hash<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<&'a BStr, E> { + take_while( + gix_hash::Kind::shortest().len_in_hex()..=gix_hash::Kind::longest().len_in_hex(), is_hex_digit_lc, - )(i) - .map(|(i, hex)| (i, hex.as_bstr())) + ) + .map(ByteSlice::as_bstr) + .parse_next(i) } -pub(crate) fn signature<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( - i: &'a [u8], -) -> IResult<&'a [u8], gix_actor::SignatureRef<'a>, E> { +pub(crate) fn signature<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>( + i: &mut &'a [u8], +) -> PResult<gix_actor::SignatureRef<'a>, E> { gix_actor::signature::decode(i) } diff --git a/vendor/gix-object/src/tag/decode.rs b/vendor/gix-object/src/tag/decode.rs index ba9460af9..73a928638 100644 --- a/vendor/gix-object/src/tag/decode.rs +++ b/vendor/gix-object/src/tag/decode.rs @@ -1,90 +1,75 @@ -use nom::{ - branch::alt, - bytes::complete::{tag, take_until, take_while, take_while1}, - character::is_alphabetic, - combinator::{all_consuming, opt, recognize}, - error::{context, ContextError, ParseError}, - sequence::{preceded, tuple}, - IResult, +use winnow::{ + combinator::{alt, delimited, eof, opt, preceded, rest, terminated}, + error::{AddContext, ParserError, StrContext}, + prelude::*, + stream::AsChar, + token::{take_until0, take_while}, }; use crate::{parse, parse::NL, BStr, ByteSlice, TagRef}; -pub fn git_tag<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(i: &'a [u8]) -> IResult<&[u8], TagRef<'a>, E> { - let (i, target) = context("object <40 lowercase hex char>", |i| { - parse::header_field(i, b"object", parse::hex_hash) - })(i)?; - - let (i, kind) = context("type <object kind>", |i| { - parse::header_field(i, b"type", take_while1(is_alphabetic)) - })(i)?; - let kind = crate::Kind::from_bytes(kind) - .map_err(|_| nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::MapRes)))?; - - let (i, tag_version) = context("tag <version>", |i| { - parse::header_field(i, b"tag", take_while1(|b| b != NL[0])) - })(i)?; - - let (i, signature) = context( - "tagger <signature>", - opt(|i| parse::header_field(i, b"tagger", parse::signature)), - )(i)?; - let (i, (message, pgp_signature)) = all_consuming(message)(i)?; - Ok(( - i, - TagRef { - target, - name: tag_version.as_bstr(), - target_kind: kind, - message, - tagger: signature, - pgp_signature, - }, - )) +pub fn git_tag<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>( + i: &mut &'a [u8], +) -> PResult<TagRef<'a>, E> { + ( + (|i: &mut _| parse::header_field(i, b"object", parse::hex_hash)) + .context(StrContext::Expected("object <40 lowercase hex char>".into())), + (|i: &mut _| parse::header_field(i, b"type", take_while(1.., AsChar::is_alpha))) + .verify_map(|kind| crate::Kind::from_bytes(kind).ok()) + .context(StrContext::Expected("type <object kind>".into())), + (|i: &mut _| parse::header_field(i, b"tag", take_while(1.., |b| b != NL[0]))) + .context(StrContext::Expected("tag <version>".into())), + opt(|i: &mut _| parse::header_field(i, b"tagger", parse::signature)) + .context(StrContext::Expected("tagger <signature>".into())), + terminated(message, eof), + ) + .map( + |(target, kind, tag_version, signature, (message, pgp_signature))| TagRef { + target, + name: tag_version.as_bstr(), + target_kind: kind, + message, + tagger: signature, + pgp_signature, + }, + ) + .parse_next(i) } -pub fn message<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], (&'a BStr, Option<&'a BStr>), E> { +pub fn message<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<(&'a BStr, Option<&'a BStr>), E> { const PGP_SIGNATURE_BEGIN: &[u8] = b"\n-----BEGIN PGP SIGNATURE-----"; const PGP_SIGNATURE_END: &[u8] = b"-----END PGP SIGNATURE-----"; if i.is_empty() { - return Ok((i, (i.as_bstr(), None))); - } - let (i, _) = tag(NL)(i)?; - fn all_to_end<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], (&'a [u8], &'a [u8]), E> { - if i.is_empty() { - // Empty message. That's OK. - return Ok((&[], (&[], &[]))); - } - // an empty signature message signals that there is none - the function signature is needed - // to work with 'alt(…)'. PGP signatures are never empty - Ok((&[], (i, &[]))) + return Ok((b"".as_bstr(), None)); } - let (i, (message, signature)) = alt(( - tuple(( - take_until(PGP_SIGNATURE_BEGIN), - preceded( - tag(NL), - recognize(tuple(( - tag(&PGP_SIGNATURE_BEGIN[1..]), - take_until(PGP_SIGNATURE_END), - tag(PGP_SIGNATURE_END), - take_while(|_| true), - ))), + delimited( + NL, + alt(( + ( + take_until0(PGP_SIGNATURE_BEGIN), + preceded( + NL, + ( + &PGP_SIGNATURE_BEGIN[1..], + take_until0(PGP_SIGNATURE_END), + PGP_SIGNATURE_END, + rest, + ) + .recognize() + .map(|signature: &[u8]| { + if signature.is_empty() { + None + } else { + Some(signature.as_bstr()) + } + }), + ), ), + rest.map(|rest: &[u8]| (rest, None)), )), - all_to_end, - ))(i)?; - let (i, _) = opt(tag(NL))(i)?; - Ok(( - i, - ( - message.as_bstr(), - if signature.is_empty() { - None - } else { - Some(signature.as_bstr()) - }, - ), - )) + opt(NL), + ) + .map(|(message, signature)| (message.as_bstr(), signature)) + .parse_next(i) } diff --git a/vendor/gix-object/src/tag/mod.rs b/vendor/gix-object/src/tag/mod.rs index 1cd353ffb..3813bfc14 100644 --- a/vendor/gix-object/src/tag/mod.rs +++ b/vendor/gix-object/src/tag/mod.rs @@ -10,10 +10,8 @@ pub mod ref_iter; impl<'a> TagRef<'a> { /// Deserialize a tag from `data`. - pub fn from_bytes(data: &'a [u8]) -> Result<TagRef<'a>, crate::decode::Error> { - decode::git_tag(data) - .map(|(_, t)| t) - .map_err(crate::decode::Error::from) + pub fn from_bytes(mut data: &'a [u8]) -> Result<TagRef<'a>, crate::decode::Error> { + decode::git_tag(&mut data).map_err(crate::decode::Error::with_err) } /// The object this tag points to as `Id`. pub fn target(&self) -> gix_hash::ObjectId { diff --git a/vendor/gix-object/src/tag/ref_iter.rs b/vendor/gix-object/src/tag/ref_iter.rs index 1138016b5..b3956ff83 100644 --- a/vendor/gix-object/src/tag/ref_iter.rs +++ b/vendor/gix-object/src/tag/ref_iter.rs @@ -1,10 +1,11 @@ use bstr::BStr; use gix_hash::{oid, ObjectId}; -use nom::{ - bytes::complete::take_while1, - character::is_alphabetic, - combinator::{all_consuming, opt}, - error::{context, ParseError}, +use winnow::{ + combinator::{eof, opt, terminated}, + error::{ParserError, StrContext}, + prelude::*, + stream::AsChar, + token::take_while, }; use crate::{bstr::ByteSlice, parse, parse::NL, tag::decode, Kind, TagRefIter}; @@ -57,13 +58,21 @@ fn missing_field() -> crate::decode::Error { } impl<'a> TagRefIter<'a> { + #[inline] fn next_inner(i: &'a [u8], state: &mut State) -> Result<(&'a [u8], Token<'a>), crate::decode::Error> { + Self::next_inner_(i, state).map_err(crate::decode::Error::with_err) + } + + fn next_inner_( + mut i: &'a [u8], + state: &mut State, + ) -> Result<(&'a [u8], Token<'a>), winnow::error::ErrMode<crate::decode::ParseError>> { use State::*; Ok(match state { Target => { - let (i, target) = context("object <40 lowercase hex char>", |i| { - parse::header_field(i, b"object", parse::hex_hash) - })(i)?; + let target = (|i: &mut _| parse::header_field(i, b"object", parse::hex_hash)) + .context(StrContext::Expected("object <40 lowercase hex char>".into())) + .parse_next(&mut i)?; *state = TargetKind; ( i, @@ -73,36 +82,30 @@ impl<'a> TagRefIter<'a> { ) } TargetKind => { - let (i, kind) = context("type <object kind>", |i| { - parse::header_field(i, b"type", take_while1(is_alphabetic)) - })(i)?; - let kind = Kind::from_bytes(kind).map_err(|_| { - #[allow(clippy::let_unit_value)] - { - let err = crate::decode::ParseError::from_error_kind(i, nom::error::ErrorKind::MapRes); - nom::Err::Error(err) - } - })?; + let kind = (|i: &mut _| parse::header_field(i, b"type", take_while(1.., AsChar::is_alpha))) + .context(StrContext::Expected("type <object kind>".into())) + .parse_next(&mut i)?; + let kind = Kind::from_bytes(kind) + .map_err(|_| winnow::error::ErrMode::from_error_kind(&i, winnow::error::ErrorKind::Verify))?; *state = Name; (i, Token::TargetKind(kind)) } Name => { - let (i, tag_version) = context("tag <version>", |i| { - parse::header_field(i, b"tag", take_while1(|b| b != NL[0])) - })(i)?; + let tag_version = (|i: &mut _| parse::header_field(i, b"tag", take_while(1.., |b| b != NL[0]))) + .context(StrContext::Expected("tag <version>".into())) + .parse_next(&mut i)?; *state = Tagger; (i, Token::Name(tag_version.as_bstr())) } Tagger => { - let (i, signature) = context( - "tagger <signature>", - opt(|i| parse::header_field(i, b"tagger", parse::signature)), - )(i)?; + let signature = opt(|i: &mut _| parse::header_field(i, b"tagger", parse::signature)) + .context(StrContext::Expected("tagger <signature>".into())) + .parse_next(&mut i)?; *state = Message; (i, Token::Tagger(signature)) } Message => { - let (i, (message, pgp_signature)) = all_consuming(decode::message)(i)?; + let (message, pgp_signature) = terminated(decode::message, eof).parse_next(&mut i)?; debug_assert!( i.is_empty(), "we should have consumed all data - otherwise iter may go forever" diff --git a/vendor/gix-object/src/tag/write.rs b/vendor/gix-object/src/tag/write.rs index 5f6d58c86..cee9e587c 100644 --- a/vendor/gix-object/src/tag/write.rs +++ b/vendor/gix-object/src/tag/write.rs @@ -21,12 +21,12 @@ impl From<Error> for io::Error { } impl crate::WriteTo for Tag { - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { - encode::trusted_header_id(b"object", &self.target, &mut out)?; - encode::trusted_header_field(b"type", self.target_kind.as_bytes(), &mut out)?; - encode::header_field(b"tag", validated_name(self.name.as_ref())?, &mut out)?; + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { + encode::trusted_header_id(b"object", &self.target, out)?; + encode::trusted_header_field(b"type", self.target_kind.as_bytes(), out)?; + encode::header_field(b"tag", validated_name(self.name.as_ref())?, out)?; if let Some(tagger) = &self.tagger { - encode::trusted_header_signature(b"tagger", &tagger.to_ref(), &mut out)?; + encode::trusted_header_signature(b"tagger", &tagger.to_ref(), out)?; } out.write_all(NL)?; @@ -58,7 +58,7 @@ impl crate::WriteTo for Tag { } impl<'a> crate::WriteTo for TagRef<'a> { - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + fn write_to(&self, mut out: &mut dyn io::Write) -> io::Result<()> { encode::trusted_header_field(b"object", self.target, &mut out)?; encode::trusted_header_field(b"type", self.target_kind.as_bytes(), &mut out)?; encode::header_field(b"tag", validated_name(self.name)?, &mut out)?; diff --git a/vendor/gix-object/src/traits.rs b/vendor/gix-object/src/traits.rs index 193cd78c3..c0c4adee2 100644 --- a/vendor/gix-object/src/traits.rs +++ b/vendor/gix-object/src/traits.rs @@ -5,7 +5,7 @@ use crate::Kind; /// Writing of objects to a `Write` implementation pub trait WriteTo { /// Write a representation of this instance to `out`. - fn write_to(&self, out: impl std::io::Write) -> std::io::Result<()>; + fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()>; /// Returns the type of this object. fn kind(&self) -> Kind; @@ -29,15 +29,15 @@ impl<T> WriteTo for &T where T: WriteTo, { - fn write_to(&self, out: impl Write) -> std::io::Result<()> { + fn write_to(&self, out: &mut dyn Write) -> std::io::Result<()> { <T as WriteTo>::write_to(self, out) } - fn size(&self) -> usize { - <T as WriteTo>::size(self) - } - fn kind(&self) -> Kind { <T as WriteTo>::kind(self) } + + fn size(&self) -> usize { + <T as WriteTo>::size(self) + } } diff --git a/vendor/gix-object/src/tree/mod.rs b/vendor/gix-object/src/tree/mod.rs index 147213d70..89e4def48 100644 --- a/vendor/gix-object/src/tree/mod.rs +++ b/vendor/gix-object/src/tree/mod.rs @@ -63,7 +63,7 @@ impl EntryMode { } /// An element of a [`TreeRef`][crate::TreeRef::entries]. -#[derive(PartialEq, Eq, Debug, Hash, Clone)] +#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct EntryRef<'a> { /// The kind of object to which `oid` is pointing. diff --git a/vendor/gix-object/src/tree/ref_iter.rs b/vendor/gix-object/src/tree/ref_iter.rs index fb3ba2dfc..be1244910 100644 --- a/vendor/gix-object/src/tree/ref_iter.rs +++ b/vendor/gix-object/src/tree/ref_iter.rs @@ -1,6 +1,7 @@ use std::convert::TryFrom; -use nom::error::ParseError; +use bstr::BStr; +use winnow::error::ParserError; use crate::{tree, tree::EntryRef, TreeRef, TreeRefIter}; @@ -13,8 +14,29 @@ impl<'a> TreeRefIter<'a> { impl<'a> TreeRef<'a> { /// Deserialize a Tree from `data`. - pub fn from_bytes(data: &'a [u8]) -> Result<TreeRef<'a>, crate::decode::Error> { - decode::tree(data).map(|(_, t)| t).map_err(crate::decode::Error::from) + pub fn from_bytes(mut data: &'a [u8]) -> Result<TreeRef<'a>, crate::decode::Error> { + decode::tree(&mut data).map_err(crate::decode::Error::with_err) + } + + /// Find an entry named `name` knowing if the entry is a directory or not, using a binary search. + /// + /// Note that it's impossible to binary search by name alone as the sort order is special. + pub fn bisect_entry(&self, name: &BStr, is_dir: bool) -> Option<EntryRef<'a>> { + static NULL_HASH: gix_hash::ObjectId = gix_hash::Kind::shortest().null(); + + let search = EntryRef { + mode: if is_dir { + tree::EntryMode::Tree + } else { + tree::EntryMode::Blob + }, + filename: name, + oid: &NULL_HASH, + }; + self.entries + .binary_search_by(|e| e.cmp(&search)) + .ok() + .map(|idx| self.entries[idx]) } /// Create an instance of the empty tree. @@ -46,12 +68,11 @@ impl<'a> Iterator for TreeRefIter<'a> { } None => { self.data = &[]; + let empty = &[] as &[u8]; #[allow(clippy::unit_arg)] - Some(Err(nom::Err::Error(crate::decode::ParseError::from_error_kind( - &[] as &[u8], - nom::error::ErrorKind::MapRes, - )) - .into())) + Some(Err(crate::decode::Error::with_err( + winnow::error::ErrMode::from_error_kind(&empty, winnow::error::ErrorKind::Verify), + ))) } } } @@ -95,14 +116,12 @@ mod decode { use std::convert::TryFrom; use bstr::ByteSlice; - use nom::{ - bytes::complete::{tag, take, take_while1, take_while_m_n}, - character::is_digit, - combinator::all_consuming, - error::ParseError, - multi::many0, - sequence::terminated, - IResult, + use winnow::{ + combinator::{eof, repeat, terminated}, + error::ParserError, + prelude::*, + stream::AsChar, + token::{take, take_while}, }; use crate::{parse::SPACE, tree, tree::EntryRef, TreeRef}; @@ -123,7 +142,7 @@ mod decode { let mode = tree::EntryMode::try_from(mode).ok()?; let (filename, i) = i.split_at(i.find_byte(0)?); let i = &i[1..]; - const HASH_LEN_FIXME: usize = 20; // TODO: know actual /desired length or we may overshoot + const HASH_LEN_FIXME: usize = 20; // TODO(SHA256): know actual/desired length or we may overshoot let (oid, i) = match i.len() { len if len < HASH_LEN_FIXME => return None, _ => i.split_at(20), @@ -138,25 +157,24 @@ mod decode { )) } - pub fn entry<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&[u8], EntryRef<'_>, E> { - let (i, mode) = terminated(take_while_m_n(5, 6, is_digit), tag(SPACE))(i)?; - let mode = tree::EntryMode::try_from(mode) - .map_err(|invalid| nom::Err::Error(E::from_error_kind(invalid, nom::error::ErrorKind::MapRes)))?; - let (i, filename) = terminated(take_while1(|b| b != NULL[0]), tag(NULL))(i)?; - let (i, oid) = take(20u8)(i)?; // TODO: make this compatible with other hash lengths - - Ok(( - i, - EntryRef { + pub fn entry<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<EntryRef<'a>, E> { + ( + terminated(take_while(5..=6, AsChar::is_dec_digit), SPACE) + .verify_map(|mode| tree::EntryMode::try_from(mode).ok()), + terminated(take_while(1.., |b| b != NULL[0]), NULL), + take(20u8), // TODO(SHA256): make this compatible with other hash lengths + ) + .map(|(mode, filename, oid): (_, &[u8], _)| EntryRef { mode, filename: filename.as_bstr(), oid: gix_hash::oid::try_from_bytes(oid).expect("we counted exactly 20 bytes"), - }, - )) + }) + .parse_next(i) } - pub fn tree<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], TreeRef<'a>, E> { - let (i, entries) = all_consuming(many0(entry))(i)?; - Ok((i, TreeRef { entries })) + pub fn tree<'a, E: ParserError<&'a [u8]>>(i: &mut &'a [u8]) -> PResult<TreeRef<'a>, E> { + terminated(repeat(0.., entry), eof) + .map(|entries| TreeRef { entries }) + .parse_next(i) } } diff --git a/vendor/gix-object/src/tree/write.rs b/vendor/gix-object/src/tree/write.rs index f826e6749..91e1dc2e0 100644 --- a/vendor/gix-object/src/tree/write.rs +++ b/vendor/gix-object/src/tree/write.rs @@ -25,7 +25,7 @@ impl From<Error> for io::Error { /// Serialization impl crate::WriteTo for Tree { /// Serialize this tree to `out` in the git internal format. - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { debug_assert_eq!( &{ let mut entries_sorted = self.entries.clone(); @@ -68,7 +68,7 @@ impl crate::WriteTo for Tree { /// Serialization impl<'a> crate::WriteTo for TreeRef<'a> { /// Serialize this tree to `out` in the git internal format. - fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { + fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> { debug_assert_eq!( &{ let mut entries_sorted = self.entries.clone(); |