rust: update rust-miniscript to v13.0.0.
What changed, and why it matters
This commit updates the BitBox02 firmware's vendored copy of the Rust 'miniscript' library to version 13.0.0, along with its dependency 'hex-conservative'. The stated reason is to reduce firmware size by about 30 KB. The change is a routine dependency refresh; the commit message and diff do not describe any security bug being fixed, and no independent security advisory is supplied.
Treat as a normal dependency update. Review the upstream rust-miniscript and hex-conservative changelogs and release notes for any security-relevant fixes, and verify the small project-owned policy.rs change compiles and passes existing tests before merging.
Security signals we found
Large dependency update with no security context
No CVE or advisory referenced in commit or supplied materials
No explicit security fix described in commit message
Vendored upstream code change may include undisclosed fixes
Evidence from the diff
The diff is almost entirely a bulk vendor of upstream crates: adding hex-conservative 0.2.1, replacing the previous hex-conservative tree with a newer version, and refreshing the miniscript source tree to v13.0.0. The only project-owned code change visible in the file list is in src/rust/bitbox02-rust/src/hww/api/bitcoin/policies.rs, but its diff is not provided. No CVE, no security changelog entry, and no vendor statement about security relevance are present in the supplied materials.
Changed components
external/vendor/miniscriptexternal/vendor/hex-conservativeexternal/vendor/hex-conservative-0.2.1src/rust/bitbox02-rust/src/hww/api/bitcoin/policies.rsInspect captured patch +16279 / −7228
diff --git a/external/vendor/hex-conservative-0.2.1/.cargo-checksum.json b/external/vendor/hex-conservative-0.2.1/.cargo-checksum.json
new file mode 100644
index 0000000..c276490
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{".cargo_vcs_info.json":"5b405520bd52759ac7430bfcbe6cbc30ca6402ecf0c6790894b8013a0ac33307",".github/workflows/fuzz.yml":"20b24076bc0689a1214547fd08f5eaf553771b820f67d901ff337f95317c19fb",".github/workflows/rust.yaml":"a5c6877eef2b75354e2bd5034eb3c27f61fbf0b389b04ebc3cf261f3e67394e7","CHANGELOG.md":"f8ff29ff61d3ea0bb2886e300b96dc9535f78462ea9d14e864ac2949fbc0a829","Cargo.lock":"f7cc7fb347ec7aa2598b16933473f9a10e8ab679b28495e7f49c2fb6f3660e2d","Cargo.toml":"edce910166ffadc7557c3ec7b55e1a310d4b5bb38fa857ae151eaac272455c42","Cargo.toml.orig":"2c803d731510733c0c07330b11d7a7aaf1f3dad9da4ec8f7f40447511e72bc86","LICENSE":"7179683e8000e6bdc9bbc60d85edf0a4ac8e76f951857f54fcb775d5886f1309","README.md":"59b0b986e0b3f53e0f646ba8c0c64d75a6d9c93e04b02298b534a856c5285b82","clippy.toml":"89cd5d45d34652463cedfae1ac5fc2602f80e4d99688772f94a80bdeead90ed1","examples/custom.rs":"677ff623158a0936c7d749d78960b7de1d7742cbaab495fdd064f255932bbb9a","examples/hexy.rs":"faf50eab5ff947dc6a0f270439fdd8508b2b6ab49e893edd696e7ff08ecea830","examples/serde.rs":"6490d1c39bfc2886b9eae1b84a7bf969cf110d1003e97ada783158b287bc8255","examples/wrap_array_display_hex_trait.rs":"25c46bf17402cba1d2b7f71a95dea691eb8555c50157df13c8e7f225ad2a4985","examples/wrap_array_fmt_traits.rs":"2be6e7d357fcbb0e7865f323dbb463fb0ddfeca97fb62f10a1557f01d9312d33","githooks/pre-commit":"897530f773ae0000a25a994119ded74dd7e6fe01eeb7438f09e751bb00ce0943","rustfmt.toml":"52a5a471073587e9f58aab6a235adbc7eb8bed44bcbb5295827613bdac91c495","src/buf_encoder.rs":"f1ab77c9b9dbb7e3b02537de364514f401e63d8133b9f0bdf8d43760651d3418","src/display.rs":"1a12a731812c2ba3b0747ee457d4b9dc19e602e951f18e8c7b57db62d2c4ea3b","src/error.rs":"a529179b4aab2a213be11d21de1b8fc072d53ae1f60f05cf6a8c242a2558dd06","src/iter.rs":"ad7b94786411cb246f827a30fe851b64bb53aed1bc03f062af7d83a16e1c6823","src/lib.rs":"82a1a55df6fdddadbab21996429d30d3f10254fa4a5a2a9aa8bb176b28f79ce8","src/parse.rs":"f4926b553136c628b06d4224a9e04b54b7ae7273a4ebdad1f2fbfbea7134b533","src/serde.rs":"e5846390c871cda61714cb3f6a1d20aec0c2d0457930c277b2dd30e288c6b019"},"package":"5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd"}
\ No newline at end of file
diff --git a/external/vendor/hex-conservative-0.2.1/.cargo_vcs_info.json b/external/vendor/hex-conservative-0.2.1/.cargo_vcs_info.json
new file mode 100644
index 0000000..9c47180
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "405a7ebf615168436e6a76004bcb40accbd48f77"
+ },
+ "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/external/vendor/hex-conservative-0.2.1/.github/workflows/fuzz.yml b/external/vendor/hex-conservative-0.2.1/.github/workflows/fuzz.yml
new file mode 100644
index 0000000..e64df35
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/.github/workflows/fuzz.yml
@@ -0,0 +1,57 @@
+# Automatically generated by fuzz/generate-files.sh
+name: Fuzz
+
+on:
+ push:
+ branches:
+ - master
+ - 'test-ci/**'
+ pull_request:
+
+jobs:
+ fuzz:
+ if: ${{ !github.event.act }}
+ runs-on: ubuntu-20.04
+ strategy:
+ fail-fast: false
+ matrix:
+ fuzz_target: [
+hex,
+encode,
+ ]
+ steps:
+ - name: Install test dependencies
+ run: sudo apt-get update -y && sudo apt-get install -y binutils-dev libunwind8-dev libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc libiberty-dev
+ - uses: actions/checkout@v2
+ - uses: actions/cache@v2
+ id: cache-fuzz
+ with:
+ path: |
+ ~/.cargo/bin
+ fuzz/target
+ target
+ key: cache-${{ matrix.target }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: 1.58
+ override: true
+ profile: minimal
+ - name: fuzz
+ run: cd fuzz && ./fuzz.sh "${{ matrix.fuzz_target }}"
+ - run: echo "${{ matrix.fuzz_target }}" >executed_${{ matrix.fuzz_target }}
+ - uses: actions/upload-artifact@v2
+ with:
+ name: executed_${{ matrix.fuzz_target }}
+ path: executed_${{ matrix.fuzz_target }}
+
+ verify-execution:
+ if: ${{ !github.event.act }}
+ needs: fuzz
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/download-artifact@v2
+ - name: Display structure of downloaded files
+ run: ls -R
+ - run: find executed_* -type f -exec cat {} + | sort > executed
+ - run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed
diff --git a/external/vendor/hex-conservative-0.2.1/.github/workflows/rust.yaml b/external/vendor/hex-conservative-0.2.1/.github/workflows/rust.yaml
new file mode 100644
index 0000000..0c2698a
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/.github/workflows/rust.yaml
@@ -0,0 +1,132 @@
+on:
+ push:
+ branches:
+ - master
+ - 'test-ci/**'
+ pull_request:
+
+name: Continuous integration
+
+jobs:
+ Stable:
+ name: Test - stable toolchain
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Checkout Crate
+ uses: actions/checkout@v3
+ - name: Checkout Toolchain
+ # https://github.com/dtolnay/rust-toolchain
+ uses: dtolnay/rust-toolchain@stable
+ - name: Running test script
+ env:
+ DO_DOCS: true
+ DO_FEATURE_MATRIX: true
+ run: ./contrib/test.sh
+
+ Beta:
+ name: Test - beta toolchain
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Checkout Crate
+ uses: actions/checkout@v3
+ - name: Checkout Toolchain
+ uses: dtolnay/rust-toolchain@beta
+ - name: Running test script
+ run: ./contrib/test.sh
+
+ Nightly:
+ name: Test - nightly toolchain
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Checkout Crate
+ uses: actions/checkout@v3
+ - name: Checkout Toolchain
+ uses: dtolnay/rust-toolchain@nightly
+ - name: Running test script
+ env:
+ DO_DOCSRS: true
+ run: ./contrib/test.sh
+
+ MSRV:
+ name: Test - 1.56.1 toolchain
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Checkout Crate
+ uses: actions/checkout@v3
+ - name: Checkout Toolchain
+ uses: dtolnay/rust-toolchain@1.56.1
+ - name: Running test script
+ env:
+ DO_FEATURE_MATRIX: true
+ run: ./contrib/test.sh
+
+ Lint:
+ name: Clippy - stable toolchain
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Checkout Crate
+ uses: actions/checkout@v3
+ - name: Checkout Toolchain
+ uses: dtolnay/rust-toolchain@stable
+ - name: Running test script
+ env:
+ DO_LINT: true
+ run: ./contrib/test.sh
+
+ Fmt:
+ name: Format - nightly toolchain
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ steps:
+ - name: Checkout Crate
+ uses: actions/checkout@v3
+ - name: Checkout Toolchain
+ uses: dtolnay/rust-toolchain@nightly
+ - name: Running test script
+ env:
+ DO_FMT: true
+ run: ./contrib/test.sh
+
+ Arch32bit:
+ name: Test 32-bit version
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Crate
+ uses: actions/checkout@v3
+ - name: Checkout Toolchain
+ uses: dtolnay/rust-toolchain@stable
+ - name: Add architecture i386
+ run: sudo dpkg --add-architecture i386
+ - name: Install i686 gcc
+ run: sudo apt-get update -y && sudo apt-get install -y gcc-multilib
+ - name: Install target
+ run: rustup target add i686-unknown-linux-gnu
+ - name: Run test on i686
+ run: cargo test --target i686-unknown-linux-gnu
+
+ Cross:
+ name: Cross test
+ if: ${{ !github.event.act }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Crate
+ uses: actions/checkout@v3
+ - name: Checkout Toolchain
+ uses: dtolnay/rust-toolchain@stable
+ - name: Install target
+ run: rustup target add s390x-unknown-linux-gnu
+ - name: install cross
+ run: cargo install cross --locked
+ - name: run cross test
+ run: cross test --target s390x-unknown-linux-gnu
diff --git a/external/vendor/hex-conservative-0.2.1/CHANGELOG.md b/external/vendor/hex-conservative-0.2.1/CHANGELOG.md
new file mode 100644
index 0000000..7c08513
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/CHANGELOG.md
@@ -0,0 +1,38 @@
+# 0.2.1 - 2024-05-17
+
+- Add a new `impl_fmt_traits` macro that can be used to implement `fmt::{LowerHex, UpperHex,
+ Display, Debug}` [#90](https://github.com/rust-bitcoin/hex-conservative/pull/90)
+
+# 0.2.0 - 2024-02-27
+
+### Breaking changes
+
+There are a bunch of breaking changes in this release, including:
+
+- Re-write the `FromHex` trait [#80](https://github.com/rust-bitcoin/hex-conservative/pull/80)
+- Revamp `BufEncoder` [#52](https://github.com/rust-bitcoin/hex-conservative/pull/52)
+- A bunch of public errors have changed.
+
+### Other improvements
+
+- Bump MSRV to 1.56.1
+- For improved ergonomics, add a prelude module [#36](https://github.com/rust-bitcoin/hex-conservative/pull/36)
+- Add a `serde` module [#37](https://github.com/rust-bitcoin/hex-conservative/pull/37)
+- Remove arbitrary padding limit [#41](https://github.com/rust-bitcoin/hex-conservative/pull/41)
+- Make `fmt_hex_exact` honour `Formatter::precision`[#81](https://github.com/rust-bitcoin/hex-conservative/pull/81)
+
+### Improve error handling
+
+- Update the derives on error types [#31](https://github.com/rust-bitcoin/hex-conservative/pull/31)
+- Hide error internal [#44](https://github.com/rust-bitcoin/hex-conservative/pull/44)
+- Return specific error from `HexToByesIter::new` [#62](https://github.com/rust-bitcoin/hex-conservative/pull/62)
+
+# 0.1.1 - 2023-07-19
+
+- [Add `test_hex_unwrap`](https://github.com/rust-bitcoin/hex-conservative/pull/24) hex parsing macro for test usage.
+- [Improve formatting](https://github.com/rust-bitcoin/hex-conservative/pull/25) hex for bytes slices e.g., support padding.
+
+# 0.1.0 - 2023-06-20 Initial Release
+
+- [Import](https://github.com/rust-bitcoin/hex-conservative/pull/1) code from the `bitcoin_hashes` and `bitcoin-internals` crates.
+- [Add `Iterator` implementations](https://github.com/rust-bitcoin/hex-conservative/pull/9)
diff --git a/external/vendor/hex-conservative-0.2.1/Cargo.lock b/external/vendor/hex-conservative-0.2.1/Cargo.lock
new file mode 100644
index 0000000..cf61369
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/Cargo.lock
@@ -0,0 +1,112 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "arrayvec"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+
+[[package]]
+name = "core2"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cf12d2dad3ed124aa116f59561428478993d69ab81ae4d30e5349c9c5b5a5f6"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "hex-conservative"
+version = "0.2.1"
+dependencies = [
+ "arrayvec",
+ "core2",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "serde"
+version = "1.0.202"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.202"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.65"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/external/vendor/hex-conservative-0.2.1/Cargo.toml b/external/vendor/hex-conservative-0.2.1/Cargo.toml
new file mode 100644
index 0000000..dd9d6f5
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/Cargo.toml
@@ -0,0 +1,86 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "hex-conservative"
+version = "0.2.1"
+authors = [
+ "Martin Habovštiak <martin.habovstiak@gmail.com>",
+ "Andrew Poelstra <apoelstra@wpsoftware.net>",
+]
+exclude = [
+ "tests",
+ "contrib",
+]
+description = "A hex encoding and decoding crate with a conservative MSRV and dependency policy."
+documentation = "https://docs.rs/hex-conservative/"
+readme = "README.md"
+keywords = [
+ "encoding",
+ "hex",
+ "hexadecimal",
+]
+categories = ["encoding"]
+license = "CC0-1.0"
+repository = "https://github.com/rust-bitcoin/hex-conservative"
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+]
+
+[[example]]
+name = "hexy"
+
+[[example]]
+name = "custom"
+
+[[example]]
+name = "wrap_array_display_hex_trait"
+
+[[example]]
+name = "wrap_array_fmt_traits"
+
+[[example]]
+name = "serde"
+required-features = [
+ "std",
+ "serde",
+]
+
+[dependencies.arrayvec]
+version = "0.7.2"
+default-features = false
+
+[dependencies.core2]
+version = "0.3.2"
+optional = true
+default-features = false
+
+[dependencies.serde]
+version = "1.0"
+optional = true
+default-features = false
+
+[dev-dependencies.serde]
+version = "1.0"
+features = ["derive"]
+
+[dev-dependencies.serde_json]
+version = "1.0"
+
+[features]
+alloc = []
+default = ["std"]
+std = ["alloc"]
diff --git a/external/vendor/hex-conservative-0.2.1/Cargo.toml.orig b/external/vendor/hex-conservative-0.2.1/Cargo.toml.orig
new file mode 100644
index 0000000..4bffbcd
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/Cargo.toml.orig
@@ -0,0 +1,51 @@
+[package]
+name = "hex-conservative"
+version = "0.2.1"
+authors = ["Martin Habovštiak <martin.habovstiak@gmail.com>", "Andrew Poelstra <apoelstra@wpsoftware.net>"]
+license = "CC0-1.0"
+repository = "https://github.com/rust-bitcoin/hex-conservative"
+documentation = "https://docs.rs/hex-conservative/"
+description = "A hex encoding and decoding crate with a conservative MSRV and dependency policy."
+categories = ["encoding"]
+keywords = ["encoding", "hex", "hexadecimal"]
+readme = "README.md"
+edition = "2018"
+exclude = ["tests", "contrib"]
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = ["--cfg", "docsrs"]
+
+[workspace]
+members = ["fuzz"]
+
+[features]
+default = ["std"]
+std = ["alloc"]
+alloc = []
+
+[dependencies]
+arrayvec = { version = "0.7.2", default-features = false }
+core2 = { version = "0.3.2", default-features = false, optional = true }
+serde = { version = "1.0", default-features = false, optional = true }
+
+
+[dev-dependencies]
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
+
+[[example]]
+name = "hexy"
+
+[[example]]
+name = "custom"
+
+[[example]]
+name = "wrap_array_display_hex_trait"
+
+[[example]]
+name = "wrap_array_fmt_traits"
+
+[[example]]
+name = "serde"
+required-features = ["std", "serde"]
diff --git a/external/vendor/hex-conservative-0.2.1/LICENSE b/external/vendor/hex-conservative-0.2.1/LICENSE
new file mode 100644
index 0000000..6ca207e
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/LICENSE
@@ -0,0 +1,122 @@
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
+
diff --git a/external/vendor/hex-conservative-0.2.1/README.md b/external/vendor/hex-conservative-0.2.1/README.md
new file mode 100644
index 0000000..546ef87
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/README.md
@@ -0,0 +1,20 @@
+# Bitcoin Hexadecimal Library
+
+General purpose hex encoding/decoding library with a conservative MSRV and dependency policy.
+
+## Minimum Supported Rust Version (MSRV)
+
+This library should compile with almost any combination of features on **Rust 1.56.1**, however we
+reserve the right to use features to guard compiler specific code so `--all-features` may not work
+using the MSRV toolchain.
+
+### Githooks
+
+To assist devs in catching errors _before_ running CI we provide some githooks. If you do not
+already have locally configured githooks you can use the ones in this repository by running, in the
+root directory of the repository:
+```
+git config --local core.hooksPath githooks/
+```
+
+Alternatively add symlinks in your `.git/hooks` directory to any of the githooks we provide.
diff --git a/external/vendor/hex-conservative-0.2.1/clippy.toml b/external/vendor/hex-conservative-0.2.1/clippy.toml
new file mode 100644
index 0000000..56ce04e
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/clippy.toml
@@ -0,0 +1 @@
+msrv = "1.56.1"
diff --git a/external/vendor/hex-conservative-0.2.1/examples/custom.rs b/external/vendor/hex-conservative-0.2.1/examples/custom.rs
new file mode 100644
index 0000000..0fc77f1
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/examples/custom.rs
@@ -0,0 +1,158 @@
+//! Demonstrate hexadecimal encoding and decoding for a type where hex is not the natural hex representation but the type can still be encoded/decoded to/from hex.
+//!
+//! For a type where hex is the natural representation see `./hexy.rs`.
+//! To wrap an array see the `./wrap_array_*` examples.
+
+use core::fmt;
+use core::str::FromStr;
+
+use hex_conservative::{DisplayHex, FromHex, HexToArrayError, HexToBytesError};
+
+fn main() {
+ let s = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
+ println!("Parse from hex: {}", s);
+
+ let hexy = ALittleBitHexy::from_hex(s).expect("the correct number of valid hex digits");
+ println!("Display ALittleBitHexy as string: {}", hexy);
+ println!("Display ALittleBitHexy as a hex: {:x}", hexy.as_hex());
+
+ #[cfg(feature = "alloc")]
+ {
+ let hex = hexy.to_lower_hex_string();
+ let from_hex = ALittleBitHexy::from_hex(&hex).expect("failed to parse hex");
+ assert_eq!(from_hex, hexy);
+ }
+}
+
+/// A struct that displays using some application specific format but also supports printing as hex.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct ALittleBitHexy {
+ // Some opaque data that should be printed as hex.
+ data: [u8; 32],
+ // Some other application data.
+ x: usize,
+}
+
+impl ALittleBitHexy {
+ /// Example constructor.
+ pub fn new(x: usize) -> Self { Self { x, data: [0_u8; 32] } }
+}
+
+impl fmt::Debug for ALittleBitHexy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Formatter::debug_struct(f, "ALittleBitHexy")
+ .field("data", &self.data.as_hex())
+ .field("x", &self.x)
+ .finish()
+ }
+}
+
+/// `Display` uses some application specific format (and roundtrips with `FromStr`).
+impl fmt::Display for ALittleBitHexy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Some application specific format:{}", self.x)
+ }
+}
+
+impl FromStr for ALittleBitHexy {
+ type Err = Error;
+ fn from_str(_: &str) -> Result<Self, Self::Err> {
+ todo!("Parse a string as formatted by `Display`")
+ }
+}
+
+// If the object can be parsed from hex, implement `FromHex`.
+
+impl FromHex for ALittleBitHexy {
+ type Error = HexToArrayError;
+
+ fn from_hex(s: &str) -> Result<Self, Self::Error> {
+ // Errors if the input is invalid
+ let data = <[u8; 32] as FromHex>::from_hex(s)?;
+ // This is a contrived example (using x==0).
+ Ok(ALittleBitHexy { data, x: 0 })
+ }
+}
+
+// Implement conversion to hex by implementing `DisplayHex` on a wrapper type.
+
+impl<'a> DisplayHex for &'a ALittleBitHexy {
+ type Display = DisplayALittleBitHexy<'a>;
+
+ fn as_hex(self) -> Self::Display { DisplayALittleBitHexy { data: &self.data } }
+
+ fn hex_reserve_suggestion(self) -> usize {
+ self.data.len().checked_mul(2).expect("the string wouldn't fit into address space")
+ }
+}
+
+/// Displays `ALittleBitHexy` as hex.
+///
+/// Created by [`<&ALittleBitHexy as DisplayHex>::as_hex`](DisplayHex::as_hex).
+pub struct DisplayALittleBitHexy<'a> {
+ data: &'a [u8],
+}
+
+impl<'a> fmt::Display for DisplayALittleBitHexy<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
+}
+
+impl<'a> fmt::Debug for DisplayALittleBitHexy<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
+}
+
+impl<'a> fmt::LowerHex for DisplayALittleBitHexy<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::LowerHex::fmt(&self.data.as_hex(), f)
+ }
+}
+
+impl<'a> fmt::UpperHex for DisplayALittleBitHexy<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::UpperHex::fmt(&self.data.as_hex(), f)
+ }
+}
+
+/// Example Error.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Error {
+ /// Conversion error while parsing hex string.
+ Conversion(HexToBytesError),
+ /// Invalid string for array.
+ Array(HexToArrayError),
+ /// Attempt to parse invalid string.
+ InvalidStringFormat,
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use Error::*;
+
+ match *self {
+ Conversion(ref e) => write!(f, "conversion error: {:?}", e),
+ Array(ref e) => write!(f, "array error: {:?}", e),
+ InvalidStringFormat => write!(f, "invalid string format"),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for Error {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ use Error::*;
+
+ match *self {
+ Conversion(ref e) => Some(e),
+ Array(ref e) => Some(e),
+ InvalidStringFormat => None,
+ }
+ }
+}
+
+impl From<HexToBytesError> for Error {
+ fn from(e: HexToBytesError) -> Self { Self::Conversion(e) }
+}
+
+impl From<HexToArrayError> for Error {
+ fn from(e: HexToArrayError) -> Self { Self::Array(e) }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/examples/hexy.rs b/external/vendor/hex-conservative-0.2.1/examples/hexy.rs
new file mode 100644
index 0000000..93f9ee4
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/examples/hexy.rs
@@ -0,0 +1,80 @@
+//! Demonstrate hexadecimal encoding and decoding for a type with a natural hex representation.
+//!
+//! For a type where hex is supported but is not the natural representation see `./custom.rs`.
+//! To wrap an array see the `./wrap_array_*` examples.
+
+use std::fmt;
+use std::str::FromStr;
+
+use hex_conservative::{fmt_hex_exact, Case, DisplayHex, FromHex, HexToArrayError};
+
+fn main() {
+ let s = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
+ println!("Parse hex from string: {}", s);
+
+ let hexy = Hexy::from_hex(s).expect("the correct number of valid hex digits");
+ let display = format!("{}", hexy);
+ println!("Display Hexy as string: {}", display);
+
+ assert_eq!(display, s);
+}
+
+/// A struct that always uses hex when in string form.
+pub struct Hexy {
+ // Some opaque data.
+ data: [u8; 32],
+}
+
+impl Hexy {
+ /// Demonstrates getting internal opaque data as a byte slice.
+ pub fn as_bytes(&self) -> &[u8] { &self.data }
+}
+
+impl fmt::Debug for Hexy {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ fmt::Formatter::debug_struct(f, "Hexy").field("data", &self.data.as_hex()).finish()
+ }
+}
+
+// We implement `Display`/`FromStr` using `LowerHex`/`FromHex` respectively, if hex was not the
+// natural representation for this type this would not be the case.
+
+impl fmt::Display for Hexy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
+}
+
+impl FromStr for Hexy {
+ type Err = HexToArrayError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> { Hexy::from_hex(s) }
+}
+
+// Implement conversion to hex by first converting our type to a byte slice.
+
+impl fmt::LowerHex for Hexy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // This is equivalent to but more performant than:
+ // fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
+ fmt_hex_exact!(f, 32, self.as_bytes(), Case::Lower)
+ }
+}
+
+impl fmt::UpperHex for Hexy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // This is equivalent to but more performant than:
+ // fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
+ fmt_hex_exact!(f, 32, self.as_bytes(), Case::Upper)
+ }
+}
+
+// And use a fixed size array to convert from hex.
+
+impl FromHex for Hexy {
+ type Error = HexToArrayError;
+
+ fn from_hex(s: &str) -> Result<Self, Self::Error> {
+ // Errors if the input is invalid
+ let a = <[u8; 32] as FromHex>::from_hex(s)?;
+ Ok(Hexy { data: a })
+ }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/examples/serde.rs b/external/vendor/hex-conservative-0.2.1/examples/serde.rs
new file mode 100644
index 0000000..ad40974
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/examples/serde.rs
@@ -0,0 +1,29 @@
+//! Demonstrate how to use the serde module with struct fields.
+
+#![allow(clippy::disallowed_names)] // Foo is a valid name.
+
+use hex_conservative as hex;
+use serde::{Deserialize, Serialize};
+
+/// Abstracts over foo.
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Foo {
+ // serialized as a hexadecimal string.
+ #[serde(with = "hex::serde")]
+ pub u: Vec<u8>,
+ // serialized as an array of decimal integers.
+ pub v: Vec<u8>,
+}
+
+fn main() {
+ let v = vec![0xde, 0xad, 0xbe, 0xef];
+
+ let foo = Foo { u: v.clone(), v };
+ let ser = serde_json::to_string(&foo).expect("failed to serialize foo");
+
+ // Prints:
+ //
+ // foo: {"u":"deadbeef","v":[222,173,190,239]}
+ //
+ println!("\nfoo: {}", ser);
+}
diff --git a/external/vendor/hex-conservative-0.2.1/examples/wrap_array_display_hex_trait.rs b/external/vendor/hex-conservative-0.2.1/examples/wrap_array_display_hex_trait.rs
new file mode 100644
index 0000000..a635005
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/examples/wrap_array_display_hex_trait.rs
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Hex encode/decode a type that wraps an array - using an implementation of the `DisplayHex` trait.
+//!
+//! For an example using the standard library `fmt` traits see `./wrap_array_fmt_traits.rs`.
+
+use hex_conservative::display::DisplayArray;
+use hex_conservative::{DisplayHex, FromHex, HexToArrayError};
+
+fn main() {
+ let hex = "00000000cafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
+ println!("\nParse from hex: {}\n", hex);
+
+ let array = <[u8; 32] as FromHex>::from_hex(hex).expect("failed to parse array");
+ let wrap = Wrap::from_hex(hex).expect("failed to parse wrapped array");
+
+ println!("Print an array using traits from the standard libraries `fmt` module along with the provided implementation of `DisplayHex`:\n");
+ println!("LowerHex: {:x}", array.as_hex());
+ println!("UpperHex: {:X}", array.as_hex());
+ println!("Display: {}", array.as_hex());
+ println!("Debug: {:?}", array.as_hex());
+ println!("Debug pretty: {:#?}", array.as_hex());
+
+ println!("\n");
+
+ println!(
+ "Print the wrapped array directly using traits from the standard libraries `fmt` module:\n"
+ );
+ println!("LowerHex: {:x}", wrap.as_hex());
+ println!("UpperHex: {:X}", wrap.as_hex());
+ println!("Display: {}", wrap.as_hex());
+ println!("Debug: {:?}", wrap.as_hex());
+ println!("Debug pretty: {:#?}", wrap.as_hex());
+
+ #[cfg(feature = "alloc")]
+ {
+ // We cannot call `to_string` on the wrapped type to allocate a string, if you wish to
+ // use that trait method see `./wrap_array_fmt_traits.rs`.
+ let array_hex = array.to_lower_hex_string();
+ let wrap_hex = wrap.to_lower_hex_string();
+ assert_eq!(array_hex, wrap_hex);
+ }
+}
+
+pub struct Wrap([u8; 32]);
+
+impl FromHex for Wrap {
+ type Error = HexToArrayError;
+
+ fn from_hex(s: &str) -> Result<Self, Self::Error> { Ok(Self(FromHex::from_hex(s)?)) }
+}
+
+/// Use `DisplayArray` to display the `Wrap` type.
+///
+// TODO: The following statement is not true because `DislpayByteSlice` does not prefix pretty debug with 0x - fix this.
+/// Alternately use `DisplayByteSlice` which will achieve exactly the same thing.
+// impl<'a> DisplayHex for &'a Wrap {
+// type Display = DisplayByteSlice<'a>;
+// fn as_hex(self) -> Self::Display { self.0.as_ref().as_hex() }
+// fn hex_reserve_suggestion(self) -> usize { self.0.as_ref().hex_reserve_suggestion() }
+// }
+impl<'a> DisplayHex for &'a Wrap {
+ type Display = DisplayArray<'a, 64>;
+ fn as_hex(self) -> Self::Display { self.0.as_hex() }
+ fn hex_reserve_suggestion(self) -> usize { 64 }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/examples/wrap_array_fmt_traits.rs b/external/vendor/hex-conservative-0.2.1/examples/wrap_array_fmt_traits.rs
new file mode 100644
index 0000000..4d1fb2d
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/examples/wrap_array_fmt_traits.rs
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Hex encode/decode a type that wraps an array - using implementations of the standard library
+//!
+//! `fmt` traits. For an example using the `DisplayHex` trait see `./wrap_array_display_hex.rs`.
+
+use core::fmt;
+use core::str::FromStr;
+
+use hex_conservative::{DisplayHex, FromHex, HexToArrayError};
+
+fn main() {
+ let hex = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
+ println!("\nParse from hex: {}\n", hex);
+
+ let array = <[u8; 32] as FromHex>::from_hex(hex).expect("failed to parse array");
+ let wrap = Wrap::from_str(hex).expect("failed to parse wrapped array from hex string");
+
+ println!("Print an array using traits from the standard libraries `fmt` module along with the provided implementation of `DisplayHex`:\n");
+ println!("LowerHex: {:x}", array.as_hex());
+ println!("UpperHex: {:X}", array.as_hex());
+ println!("Display: {}", array.as_hex());
+ println!("Debug: {:?}", array.as_hex());
+ println!("Debug pretty: {:#?}", array.as_hex());
+
+ println!("\n");
+
+ println!(
+ "Print the wrapped array directly using traits from the standard libraries `fmt` module:\n"
+ );
+ println!("LowerHex: {:x}", wrap);
+ println!("UpperHex: {:X}", wrap);
+ println!("Display: {}", wrap);
+ println!("Debug: {:?}", wrap);
+ println!("Debug pretty: {:#?}", wrap);
+
+ // We cannot call `to_lower_hex_string` on the wrapped type to allocate a string, if you wish to
+ // use that trait method see `./wrap_array_display_hex_trait.rs`.
+ let array_hex = array.as_hex().to_string();
+ let wrap_hex = wrap.to_string();
+ assert_eq!(array_hex, wrap_hex);
+}
+
+pub struct Wrap([u8; 32]);
+
+impl fmt::Debug for Wrap {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ fmt::Formatter::debug_tuple(f, "Wrap").field(&self.0.as_hex()).finish()
+ }
+}
+
+impl fmt::Display for Wrap {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ fmt::Display::fmt(&self.0.as_hex(), f)
+ }
+}
+
+impl fmt::LowerHex for Wrap {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ fmt::LowerHex::fmt(&self.0.as_hex(), f)
+ }
+}
+
+impl fmt::UpperHex for Wrap {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ fmt::LowerHex::fmt(&self.0.as_hex(), f)
+ }
+}
+
+impl FromStr for Wrap {
+ type Err = HexToArrayError;
+ fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Self(FromHex::from_hex(s)?)) }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/githooks/pre-commit b/external/vendor/hex-conservative-0.2.1/githooks/pre-commit
new file mode 100755
index 0000000..5bb2c48
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/githooks/pre-commit
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# Verify what is about to be committed. Called by "git commit" with no
+# arguments. The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+ against=HEAD
+else
+ # Initial commit: diff against an empty tree object
+ against=$(git hash-object -t tree /dev/null)
+fi
+
+# If you want to allow non-ASCII filenames set this variable to true.
+allownonascii=$(git config --bool hooks.allownonascii)
+
+# Redirect output to stderr.
+exec 1>&2
+
+# Cross platform projects tend to avoid non-ASCII filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+ # Note that the use of brackets around a tr range is ok here, (it's
+ # even required, for portability to Solaris 10's /usr/bin/tr), since
+ # the square bracket bytes happen to fall in the designated range.
+ test $(git diff --cached --name-only --diff-filter=A -z $against |
+ LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
+then
+ cat <<\EOF
+Error: Attempt to add a non-ASCII file name.
+
+This can cause problems if you want to work with people on other platforms.
+
+To be portable it is advisable to rename the file.
+
+If you know what you are doing you can disable this check using:
+
+ git config hooks.allownonascii true
+EOF
+ exit 1
+fi
+
+# If there are whitespace errors, print the offending file names and fail.
+git diff-index --check --cached $against -- || exit 1
+
+# Check that code lints cleanly.
+cargo clippy --all-features -- -D warnings || exit 1
+
+# Check that there are no formatting issues.
+cargo +nightly fmt --check || exit 1
diff --git a/external/vendor/hex-conservative-0.2.1/rustfmt.toml b/external/vendor/hex-conservative-0.2.1/rustfmt.toml
new file mode 100644
index 0000000..ab4989f
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/rustfmt.toml
@@ -0,0 +1,78 @@
+ignore = []
+
+hard_tabs = false
+tab_spaces = 4
+newline_style = "Auto"
+indent_style = "Block"
+
+max_width = 100 # This is number of characters.
+# `use_small_heuristics` is ignored if the granular width config values are explicitly set.
+use_small_heuristics = "Max" # "Max" == All granular width settings same as `max_width`.
+# # Granular width configuration settings. These are percentages of `max_width`.
+# fn_call_width = 60
+# attr_fn_like_width = 70
+# struct_lit_width = 18
+# struct_variant_width = 35
+# array_width = 60
+# chain_width = 60
+# single_line_if_else_max_width = 50
+
+wrap_comments = false
+format_code_in_doc_comments = false
+comment_width = 100 # Default 80
+normalize_comments = false
+normalize_doc_attributes = false
+format_strings = false
+format_macro_matchers = false
+format_macro_bodies = true
+hex_literal_case = "Preserve"
+empty_item_single_line = true
+struct_lit_single_line = true
+fn_single_line = true # Default false
+where_single_line = false
+imports_indent = "Block"
+imports_layout = "Mixed"
+imports_granularity = "Module" # Default "Preserve"
+group_imports = "StdExternalCrate" # Default "Preserve"
+reorder_imports = true
+reorder_modules = true
+reorder_impl_items = false
+type_punctuation_density = "Wide"
+space_before_colon = false
+space_after_colon = true
+spaces_around_ranges = false
+binop_separator = "Front"
+remove_nested_parens = true
+combine_control_expr = true
+overflow_delimited_expr = false
+struct_field_align_threshold = 0
+enum_discrim_align_threshold = 0
+match_arm_blocks = false # Default true
+match_arm_leading_pipes = "Never"
+force_multiline_blocks = false
+fn_params_layout = "Tall"
+brace_style = "SameLineWhere"
+control_brace_style = "AlwaysSameLine"
+trailing_semicolon = true
+trailing_comma = "Vertical"
+match_block_trailing_comma = false
+blank_lines_upper_bound = 1
+blank_lines_lower_bound = 0
+edition = "2018"
+version = "One"
+inline_attribute_width = 0
+format_generated_files = true
+merge_derives = true
+use_try_shorthand = false
+use_field_init_shorthand = false
+force_explicit_abi = true
+condense_wildcard_suffixes = false
+color = "Auto"
+unstable_features = false
+disable_all_formatting = false
+skip_children = false
+hide_parse_errors = false
+error_on_line_overflow = false
+error_on_unformatted = false
+emit_mode = "Files"
+make_backup = false
diff --git a/external/vendor/hex-conservative-0.2.1/src/buf_encoder.rs b/external/vendor/hex-conservative-0.2.1/src/buf_encoder.rs
new file mode 100644
index 0000000..0aa1802
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/src/buf_encoder.rs
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Implements a buffered encoder.
+//!
+//! This is a low-level module, most uses should be satisfied by the `display` module instead.
+//!
+//! The main type in this module is [`BufEncoder`] which provides buffered hex encoding.
+//! `BufEncoder` is faster than the usual `write!(f, "{02x}", b)?` in a for loop because it reduces
+//! dynamic dispatch and decreases the number of allocations if a `String` is being created.
+
+use core::borrow::Borrow;
+
+use arrayvec::ArrayString;
+
+use super::Case;
+
+/// Hex-encodes bytes into the provided buffer.
+///
+/// This is an important building block for fast hex-encoding. Because string writing tools
+/// provided by `core::fmt` involve dynamic dispatch and don't allow reserving capacity in strings
+/// buffering the hex and then formatting it is significantly faster.
+pub struct BufEncoder<const CAP: usize> {
+ buf: ArrayString<CAP>,
+}
+
+impl<const CAP: usize> BufEncoder<CAP> {
+ const _CHECK_EVEN_CAPACITY: () = [(); 1][CAP % 2];
+
+ /// Creates an empty `BufEncoder`.
+ #[inline]
+ pub fn new() -> Self { BufEncoder { buf: ArrayString::new() } }
+
+ /// Encodes `byte` as hex in given `case` and appends it to the buffer.
+ ///
+ /// ## Panics
+ ///
+ /// The method panics if the buffer is full.
+ #[inline]
+ #[track_caller]
+ pub fn put_byte(&mut self, byte: u8, case: Case) {
+ self.buf.push_str(&case.table().byte_to_hex(byte));
+ }
+
+ /// Encodes `bytes` as hex in given `case` and appends them to the buffer.
+ ///
+ /// ## Panics
+ ///
+ /// The method panics if the bytes wouldn't fit the buffer.
+ #[inline]
+ #[track_caller]
+ pub fn put_bytes<I>(&mut self, bytes: I, case: Case)
+ where
+ I: IntoIterator,
+ I::Item: Borrow<u8>,
+ {
+ self.put_bytes_inner(bytes.into_iter(), case)
+ }
+
+ #[inline]
+ #[track_caller]
+ fn put_bytes_inner<I>(&mut self, bytes: I, case: Case)
+ where
+ I: Iterator,
+ I::Item: Borrow<u8>,
+ {
+ // May give the compiler better optimization opportunity
+ if let Some(max) = bytes.size_hint().1 {
+ assert!(max <= self.space_remaining());
+ }
+ for byte in bytes {
+ self.put_byte(*byte.borrow(), case);
+ }
+ }
+
+ /// Encodes as many `bytes` as fit into the buffer as hex and return the remainder.
+ ///
+ /// This method works just like `put_bytes` but instead of panicking it returns the unwritten
+ /// bytes. The method returns an empty slice if all bytes were written
+ #[must_use = "this may write only part of the input buffer"]
+ #[inline]
+ #[track_caller]
+ pub fn put_bytes_min<'a>(&mut self, bytes: &'a [u8], case: Case) -> &'a [u8] {
+ let to_write = self.space_remaining().min(bytes.len());
+ self.put_bytes(&bytes[..to_write], case);
+ &bytes[to_write..]
+ }
+
+ /// Returns true if no more bytes can be written into the buffer.
+ #[inline]
+ pub fn is_full(&self) -> bool { self.space_remaining() == 0 }
+
+ /// Returns the written bytes as a hex `str`.
+ #[inline]
+ pub fn as_str(&self) -> &str { &self.buf }
+
+ /// Resets the buffer to become empty.
+ #[inline]
+ pub fn clear(&mut self) { self.buf.clear(); }
+
+ /// How many bytes can be written to this buffer.
+ ///
+ /// Note that this returns the number of bytes before encoding, not number of hex digits.
+ #[inline]
+ pub fn space_remaining(&self) -> usize { self.buf.remaining_capacity() / 2 }
+
+ pub(crate) fn put_filler(&mut self, filler: char, max_count: usize) -> usize {
+ let mut buf = [0; 4];
+ let filler = filler.encode_utf8(&mut buf);
+ let max_capacity = self.buf.remaining_capacity() / filler.len();
+ let to_write = max_capacity.min(max_count);
+
+ for _ in 0..to_write {
+ self.buf.push_str(filler);
+ }
+
+ to_write
+ }
+}
+
+impl<const CAP: usize> Default for BufEncoder<CAP> {
+ fn default() -> Self { Self::new() }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn empty() {
+ let encoder = BufEncoder::<2>::new();
+ assert_eq!(encoder.as_str(), "");
+ assert!(!encoder.is_full());
+ }
+
+ #[test]
+ fn single_byte_exact_buf() {
+ let mut encoder = BufEncoder::<2>::new();
+ assert_eq!(encoder.space_remaining(), 1);
+ encoder.put_byte(42, Case::Lower);
+ assert_eq!(encoder.as_str(), "2a");
+ assert_eq!(encoder.space_remaining(), 0);
+ assert!(encoder.is_full());
+ encoder.clear();
+ assert_eq!(encoder.space_remaining(), 1);
+ assert!(!encoder.is_full());
+ encoder.put_byte(42, Case::Upper);
+ assert_eq!(encoder.as_str(), "2A");
+ assert_eq!(encoder.space_remaining(), 0);
+ assert!(encoder.is_full());
+ }
+
+ #[test]
+ fn single_byte_oversized_buf() {
+ let mut encoder = BufEncoder::<4>::new();
+ assert_eq!(encoder.space_remaining(), 2);
+ encoder.put_byte(42, Case::Lower);
+ assert_eq!(encoder.space_remaining(), 1);
+ assert_eq!(encoder.as_str(), "2a");
+ assert!(!encoder.is_full());
+ encoder.clear();
+ assert_eq!(encoder.space_remaining(), 2);
+ encoder.put_byte(42, Case::Upper);
+ assert_eq!(encoder.as_str(), "2A");
+ assert_eq!(encoder.space_remaining(), 1);
+ assert!(!encoder.is_full());
+ }
+
+ #[test]
+ fn two_bytes() {
+ let mut encoder = BufEncoder::<4>::new();
+ encoder.put_byte(42, Case::Lower);
+ assert_eq!(encoder.space_remaining(), 1);
+ encoder.put_byte(255, Case::Lower);
+ assert_eq!(encoder.space_remaining(), 0);
+ assert_eq!(encoder.as_str(), "2aff");
+ assert!(encoder.is_full());
+ encoder.clear();
+ assert!(!encoder.is_full());
+ encoder.put_byte(42, Case::Upper);
+ encoder.put_byte(255, Case::Upper);
+ assert_eq!(encoder.as_str(), "2AFF");
+ assert!(encoder.is_full());
+ }
+
+ #[test]
+ fn put_bytes_min() {
+ let mut encoder = BufEncoder::<2>::new();
+ let remainder = encoder.put_bytes_min(b"", Case::Lower);
+ assert_eq!(remainder, b"");
+ assert_eq!(encoder.as_str(), "");
+ let remainder = encoder.put_bytes_min(b"*", Case::Lower);
+ assert_eq!(remainder, b"");
+ assert_eq!(encoder.as_str(), "2a");
+ encoder.clear();
+ let remainder = encoder.put_bytes_min(&[42, 255], Case::Lower);
+ assert_eq!(remainder, &[255]);
+ assert_eq!(encoder.as_str(), "2a");
+ }
+
+ #[test]
+ fn same_as_fmt() {
+ use core::fmt::{self, Write};
+
+ struct Writer {
+ buf: [u8; 2],
+ pos: usize,
+ }
+
+ impl Writer {
+ fn as_str(&self) -> &str { core::str::from_utf8(&self.buf[..self.pos]).unwrap() }
+ }
+
+ impl Write for Writer {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ assert!(self.pos <= 2);
+ if s.len() > 2 - self.pos {
+ Err(fmt::Error)
+ } else {
+ self.buf[self.pos..(self.pos + s.len())].copy_from_slice(s.as_bytes());
+ self.pos += s.len();
+ Ok(())
+ }
+ }
+ }
+
+ let mut writer = Writer { buf: [0u8; 2], pos: 0 };
+ let mut encoder = BufEncoder::<2>::new();
+
+ for i in 0..=255 {
+ write!(writer, "{:02x}", i).unwrap();
+ encoder.put_byte(i, Case::Lower);
+ assert_eq!(encoder.as_str(), writer.as_str());
+ writer.pos = 0;
+ encoder.clear();
+ }
+ for i in 0..=255 {
+ write!(writer, "{:02X}", i).unwrap();
+ encoder.put_byte(i, Case::Upper);
+ assert_eq!(encoder.as_str(), writer.as_str());
+ writer.pos = 0;
+ encoder.clear();
+ }
+ }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/src/display.rs b/external/vendor/hex-conservative-0.2.1/src/display.rs
new file mode 100644
index 0000000..8818660
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/src/display.rs
@@ -0,0 +1,760 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Helpers for displaying bytes as hex strings.
+//!
+//! This module provides a trait for displaying things as hex as well as an implementation for
+//! `&[u8]`.
+//!
+//! For arrays and slices we support padding and precision for length < 512 bytes.
+//!
+//! # Examples
+//!
+//! ```
+//! use hex_conservative::DisplayHex;
+//!
+//! // Display as hex.
+//! let v = vec![0xde, 0xad, 0xbe, 0xef];
+//! assert_eq!(format!("{}", v.as_hex()), "deadbeef");
+//!
+//! // Get the most significant bytes.
+//! let v = vec![0x01, 0x23, 0x45, 0x67];
+//! assert_eq!(format!("{0:.4}", v.as_hex()), "0123");
+//!
+//! // Padding with zeros
+//! let v = vec![0xab; 2];
+//! assert_eq!(format!("{:0>8}", v.as_hex()), "0000abab");
+//!```
+
+#[cfg(all(feature = "alloc", not(feature = "std")))]
+use alloc::string::String;
+use core::borrow::Borrow;
+use core::fmt;
+
+use super::Case;
+use crate::buf_encoder::BufEncoder;
+
+/// Extension trait for types that can be displayed as hex.
+///
+/// Types that have a single, obvious text representation being hex should **not** implement this
+/// trait and simply implement `Display` instead.
+///
+/// This trait should be generally implemented for references only. We would prefer to use GAT but
+/// that is beyond our MSRV. As a lint we require the `IsRef` trait which is implemented for all
+/// references.
+pub trait DisplayHex: Copy + sealed::IsRef {
+ /// The type providing [`fmt::Display`] implementation.
+ ///
+ /// This is usually a wrapper type holding a reference to `Self`.
+ type Display: fmt::Display + fmt::Debug + fmt::LowerHex + fmt::UpperHex;
+
+ /// Display `Self` as a continuous sequence of ASCII hex chars.
+ fn as_hex(self) -> Self::Display;
+
+ /// Create a lower-hex-encoded string.
+ ///
+ /// A shorthand for `to_hex_string(Case::Lower)`, so that `Case` doesn't need to be imported.
+ ///
+ /// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
+ #[cfg(feature = "alloc")]
+ fn to_lower_hex_string(self) -> String { self.to_hex_string(Case::Lower) }
+
+ /// Create an upper-hex-encoded string.
+ ///
+ /// A shorthand for `to_hex_string(Case::Upper)`, so that `Case` doesn't need to be imported.
+ ///
+ /// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
+ #[cfg(feature = "alloc")]
+ fn to_upper_hex_string(self) -> String { self.to_hex_string(Case::Upper) }
+
+ /// Create a hex-encoded string.
+ ///
+ /// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
+ #[cfg(feature = "alloc")]
+ fn to_hex_string(self, case: Case) -> String {
+ let mut string = String::new();
+ self.append_hex_to_string(case, &mut string);
+ string
+ }
+
+ /// Appends hex-encoded content to an existing `String`.
+ ///
+ /// This may be faster than `write!(string, "{:x}", self.as_hex())` because it uses
+ /// `hex_reserve_sugggestion`.
+ #[cfg(feature = "alloc")]
+ fn append_hex_to_string(self, case: Case, string: &mut String) {
+ use fmt::Write;
+
+ string.reserve(self.hex_reserve_suggestion());
+ match case {
+ Case::Lower => write!(string, "{:x}", self.as_hex()),
+ Case::Upper => write!(string, "{:X}", self.as_hex()),
+ }
+ .unwrap_or_else(|_| {
+ let name = core::any::type_name::<Self::Display>();
+ // We don't expect `std` to ever be buggy, so the bug is most likely in the `Display`
+ // impl of `Self::Display`.
+ panic!("The implementation of Display for {} returned an error when it shouldn't", name)
+ })
+ }
+
+ /// Hints how much bytes to reserve when creating a `String`.
+ ///
+ /// Implementors that know the number of produced bytes upfront should override this.
+ /// Defaults to 0.
+ ///
+ // We prefix the name with `hex_` to avoid potential collision with other methods.
+ fn hex_reserve_suggestion(self) -> usize { 0 }
+}
+
+mod sealed {
+ /// Trait marking a shared reference.
+ pub trait IsRef: Copy {}
+
+ impl<T: ?Sized> IsRef for &'_ T {}
+}
+
+impl<'a> DisplayHex for &'a [u8] {
+ type Display = DisplayByteSlice<'a>;
+
+ #[inline]
+ fn as_hex(self) -> Self::Display { DisplayByteSlice { bytes: self } }
+
+ #[inline]
+ fn hex_reserve_suggestion(self) -> usize {
+ // Since the string wouldn't fit into address space if this overflows (actually even for
+ // smaller amounts) it's better to panic right away. It should also give the optimizer
+ // better opportunities.
+ self.len().checked_mul(2).expect("the string wouldn't fit into address space")
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'a> DisplayHex for &'a alloc::vec::Vec<u8> {
+ type Display = DisplayByteSlice<'a>;
+
+ #[inline]
+ fn as_hex(self) -> Self::Display { DisplayByteSlice { bytes: self } }
+
+ #[inline]
+ fn hex_reserve_suggestion(self) -> usize {
+ // Since the string wouldn't fit into address space if this overflows (actually even for
+ // smaller amounts) it's better to panic right away. It should also give the optimizer
+ // better opportunities.
+ self.len().checked_mul(2).expect("the string wouldn't fit into address space")
+ }
+}
+
+/// Displays byte slice as hex.
+///
+/// Created by [`<&[u8] as DisplayHex>::as_hex`](DisplayHex::as_hex).
+pub struct DisplayByteSlice<'a> {
+ // pub because we want to keep lengths in sync
+ pub(crate) bytes: &'a [u8],
+}
+
+impl<'a> DisplayByteSlice<'a> {
+ fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
+ use fmt::Write;
+ // There are at least two optimizations left:
+ //
+ // * Reusing the buffer (encoder) which may decrease the number of virtual calls
+ // * Not recursing, avoiding another 1024B allocation and zeroing
+ //
+ // This would complicate the code so I was too lazy to do them but feel free to send a PR!
+
+ let mut encoder = BufEncoder::<1024>::new();
+
+ let pad_right = if let Some(width) = f.width() {
+ let string_len = match f.precision() {
+ Some(max) if self.bytes.len() * 2 > (max + 1) / 2 => max,
+ Some(_) | None => self.bytes.len() * 2,
+ };
+
+ if string_len < width {
+ let (left, right) = match f.align().unwrap_or(fmt::Alignment::Left) {
+ fmt::Alignment::Left => (0, width - string_len),
+ fmt::Alignment::Right => (width - string_len, 0),
+ fmt::Alignment::Center =>
+ ((width - string_len) / 2, (width - string_len + 1) / 2),
+ };
+ // Avoid division by zero and optimize for common case.
+ if left > 0 {
+ let c = f.fill();
+ let chunk_len = encoder.put_filler(c, left);
+ let padding = encoder.as_str();
+ for _ in 0..(left / chunk_len) {
+ f.write_str(padding)?;
+ }
+ f.write_str(&padding[..((left % chunk_len) * c.len_utf8())])?;
+ encoder.clear();
+ }
+ right
+ } else {
+ 0
+ }
+ } else {
+ 0
+ };
+
+ match f.precision() {
+ Some(max) if self.bytes.len() > (max + 1) / 2 => {
+ write!(f, "{}", self.bytes[..(max / 2)].as_hex())?;
+ if max % 2 == 1 && self.bytes.len() > max / 2 + 1 {
+ f.write_char(
+ case.table().byte_to_hex(self.bytes[max / 2 + 1]).as_bytes()[1].into(),
+ )?;
+ }
+ }
+ Some(_) | None => {
+ let mut chunks = self.bytes.chunks_exact(512);
+ for chunk in &mut chunks {
+ encoder.put_bytes(chunk, case);
+ f.write_str(encoder.as_str())?;
+ encoder.clear();
+ }
+ encoder.put_bytes(chunks.remainder(), case);
+ f.write_str(encoder.as_str())?;
+ }
+ }
+
+ // Avoid division by zero and optimize for common case.
+ if pad_right > 0 {
+ encoder.clear();
+ let c = f.fill();
+ let chunk_len = encoder.put_filler(c, pad_right);
+ let padding = encoder.as_str();
+ for _ in 0..(pad_right / chunk_len) {
+ f.write_str(padding)?;
+ }
+ f.write_str(&padding[..((pad_right % chunk_len) * c.len_utf8())])?;
+ }
+ Ok(())
+ }
+}
+
+impl<'a> fmt::Display for DisplayByteSlice<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
+}
+
+impl<'a> fmt::Debug for DisplayByteSlice<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
+}
+
+impl<'a> fmt::LowerHex for DisplayByteSlice<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
+}
+
+impl<'a> fmt::UpperHex for DisplayByteSlice<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
+}
+
+/// Displays byte array as hex.
+///
+/// Created by [`<&[u8; CAP / 2] as DisplayHex>::as_hex`](DisplayHex::as_hex).
+pub struct DisplayArray<'a, const CAP: usize> {
+ array: &'a [u8],
+}
+
+impl<'a, const CAP: usize> DisplayArray<'a, CAP> {
+ /// Creates the wrapper.
+ ///
+ /// # Panics
+ ///
+ /// When the length of array is greater than capacity / 2.
+ #[inline]
+ fn new(array: &'a [u8]) -> Self {
+ assert!(array.len() <= CAP / 2);
+ DisplayArray { array }
+ }
+
+ fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
+ let mut encoder = BufEncoder::<CAP>::new();
+ encoder.put_bytes(self.array, case);
+ f.pad_integral(true, "0x", encoder.as_str())
+ }
+}
+
+impl<'a, const LEN: usize> fmt::Display for DisplayArray<'a, LEN> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
+}
+
+impl<'a, const LEN: usize> fmt::Debug for DisplayArray<'a, LEN> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
+}
+
+impl<'a, const LEN: usize> fmt::LowerHex for DisplayArray<'a, LEN> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
+}
+
+impl<'a, const LEN: usize> fmt::UpperHex for DisplayArray<'a, LEN> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
+}
+
+macro_rules! impl_array_as_hex {
+ ($($len:expr),*) => {
+ $(
+ impl<'a> DisplayHex for &'a [u8; $len] {
+ type Display = DisplayArray<'a, {$len * 2}>;
+
+ fn as_hex(self) -> Self::Display {
+ DisplayArray::new(self)
+ }
+ }
+ )*
+ }
+}
+
+impl_array_as_hex!(
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 32, 33, 64, 65, 128, 256, 512, 1024,
+ 2048, 4096
+);
+
+/// Format known-length array as hex.
+///
+/// This supports all formatting options of formatter and may be faster than calling `as_hex()` on
+/// an arbitrary `&[u8]`. Note that the implementation intentionally keeps leading zeros even when
+/// not requested. This is designed to display values such as hashes and keys and removing leading
+/// zeros would be confusing.
+///
+/// Note that the bytes parameter is `IntoIterator` this means that if you would like to do some
+/// manipulation to the byte array before formatting then you can. For example `bytes.iter().rev()`
+/// to print the array backwards.
+///
+/// ## Parameters
+///
+/// * `$formatter` - a [`fmt::Formatter`].
+/// * `$len` known length of `$bytes`, must be a const expression.
+/// * `$bytes` - bytes to be encoded, most likely a reference to an array.
+/// * `$case` - value of type [`Case`] determining whether to format as lower or upper case.
+///
+/// ## Panics
+///
+/// This macro panics if `$len` is not equal to `$bytes.len()`. It also fails to compile if `$len`
+/// is more than half of `usize::MAX`.
+#[macro_export]
+macro_rules! fmt_hex_exact {
+ ($formatter:expr, $len:expr, $bytes:expr, $case:expr) => {{
+ // statically check $len
+ #[allow(deprecated)]
+ const _: () = [()][($len > usize::MAX / 2) as usize];
+ assert_eq!($bytes.len(), $len);
+ $crate::display::fmt_hex_exact_fn::<_, { $len * 2 }>($formatter, $bytes, $case)
+ }};
+}
+pub use fmt_hex_exact;
+
+/// Adds `core::fmt` trait implementations to type `$ty`.
+///
+/// Implements:
+///
+/// - `fmt::{LowerHex, UpperHex}` using [`fmt_hex_exact`].
+/// - `fmt::{Display, Debug}` by calling `LowerHex`.
+///
+/// Requires:
+///
+/// - `$ty` must implement `IntoIterator<Item=Borrow<u8>>`.
+///
+/// ## Parameters
+///
+/// * `$ty` - the type to implement traits on.
+/// * `$len` - known length of `$bytes`, must be a const expression.
+/// * `$bytes` - bytes to be encoded, most likely a reference to an array.
+/// * `$reverse` - true if you want the array to be displayed backwards.
+/// * `$gen: $gent` - optional generic type(s) and trait bound(s) to put on `$ty` e.g, `F: Foo`.
+///
+/// ## Examples
+///
+/// ```
+/// # use core::borrow::Borrow;
+/// # use hex_conservative::impl_fmt_traits;
+/// struct Wrapper([u8; 4]);
+///
+/// impl Borrow<[u8]> for Wrapper {
+/// fn borrow(&self) -> &[u8] { &self.0[..] }
+/// }
+///
+/// impl_fmt_traits! {
+/// impl fmt_traits for Wrapper {
+/// const LENGTH: usize = 4;
+/// }
+/// }
+///
+/// let w = Wrapper([0x12, 0x34, 0x56, 0x78]);
+/// assert_eq!(format!("{}", w), "12345678");
+/// ```
+///
+/// We support generics on `$ty`:
+///
+/// ```
+/// # use core::borrow::Borrow;
+/// # use core::marker::PhantomData;
+/// # use hex_conservative::impl_fmt_traits;
+/// struct Wrapper<T>([u8; 4], PhantomData<T>);
+///
+/// // `Clone` is just some arbitrary trait.
+/// impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
+/// fn borrow(&self) -> &[u8] { &self.0[..] }
+/// }
+///
+/// impl_fmt_traits! {
+/// impl<T: Clone> fmt_traits for Wrapper<T> {
+/// const LENGTH: usize = 4;
+/// }
+/// }
+///
+/// let w = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
+/// assert_eq!(format!("{}", w), "12345678");
+/// ```
+///
+/// And also, as is required by `rust-bitcoin`, we support displaying
+/// the hex string byte-wise backwards:
+///
+/// ```
+/// # use core::borrow::Borrow;
+/// # use hex_conservative::impl_fmt_traits;
+/// struct Wrapper([u8; 4]);
+///
+/// impl Borrow<[u8]> for Wrapper {
+/// fn borrow(&self) -> &[u8] { &self.0[..] }
+/// }
+///
+/// impl_fmt_traits! {
+/// #[display_backward(true)]
+/// impl fmt_traits for Wrapper {
+/// const LENGTH: usize = 4;
+/// }
+/// }
+/// let w = Wrapper([0x12, 0x34, 0x56, 0x78]);
+/// assert_eq!(format!("{}", w), "78563412");
+/// ```
+#[macro_export]
+macro_rules! impl_fmt_traits {
+ // Without generic and trait bounds and without display_backward attribute.
+ (impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
+ $crate::impl_fmt_traits! {
+ #[display_backward(false)]
+ impl<> fmt_traits for $ty<> {
+ const LENGTH: usize = $len;
+ }
+ }
+ };
+ // Without generic and trait bounds and with display_backward attribute.
+ (#[display_backward($reverse:expr)] impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
+ $crate::impl_fmt_traits! {
+ #[display_backward($reverse)]
+ impl<> fmt_traits for $ty<> {
+ const LENGTH: usize = $len;
+ }
+ }
+ };
+ // With generic and trait bounds and without display_backward attribute.
+ (impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
+ $crate::impl_fmt_traits! {
+ #[display_backward(false)]
+ impl<$($gen: $gent),*> fmt_traits for $ty<$($unused),*> {
+ const LENGTH: usize = $len;
+ }
+ }
+ };
+ // With generic and trait bounds and display_backward attribute.
+ (#[display_backward($reverse:expr)] impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
+ impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
+ #[inline]
+ fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
+ let case = $crate::Case::Lower;
+
+ if $reverse {
+ let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
+ $crate::fmt_hex_exact!(f, $len, bytes, case)
+ } else {
+ let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
+ $crate::fmt_hex_exact!(f, $len, bytes, case)
+ }
+ }
+ }
+
+ impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
+ #[inline]
+ fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
+ let case = $crate::Case::Upper;
+
+ if $reverse {
+ let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
+ $crate::fmt_hex_exact!(f, $len, bytes, case)
+ } else {
+ let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
+ $crate::fmt_hex_exact!(f, $len, bytes, case)
+ }
+ }
+ }
+
+ impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
+ #[inline]
+ fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
+ $crate::_export::_core::fmt::LowerHex::fmt(self, f)
+ }
+ }
+
+ impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
+ #[inline]
+ fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
+ $crate::_export::_core::fmt::LowerHex::fmt(&self, f)
+ }
+ }
+ };
+}
+pub use impl_fmt_traits;
+
+// Implementation detail of `write_hex_exact` macro to de-duplicate the code
+//
+// Whether hex is an integer or a string is debatable, we cater a little bit to each.
+// - We support users adding `0x` prefix using "{:#}" (treating hex like an integer).
+// - We support limiting the output using precision "{:.10}" (treating hex like a string).
+#[doc(hidden)]
+#[inline]
+pub fn fmt_hex_exact_fn<I, const N: usize>(
+ f: &mut fmt::Formatter,
+ bytes: I,
+ case: Case,
+) -> fmt::Result
+where
+ I: IntoIterator,
+ I::Item: Borrow<u8>,
+{
+ let mut encoder = BufEncoder::<N>::new();
+ encoder.put_bytes(bytes, case);
+ let encoded = encoder.as_str();
+
+ if let Some(precision) = f.precision() {
+ if encoded.len() > precision {
+ return f.pad_integral(true, "0x", &encoded[..precision]);
+ }
+ }
+ f.pad_integral(true, "0x", encoded)
+}
+
+#[cfg(test)]
+mod tests {
+ #[cfg(feature = "alloc")]
+ use super::*;
+
+ #[cfg(feature = "alloc")]
+ mod alloc {
+ use core::marker::PhantomData;
+
+ use super::*;
+
+ fn check_encoding(bytes: &[u8]) {
+ use core::fmt::Write;
+
+ let s1 = bytes.to_lower_hex_string();
+ let mut s2 = String::with_capacity(bytes.len() * 2);
+ for b in bytes {
+ write!(s2, "{:02x}", b).unwrap();
+ }
+ assert_eq!(s1, s2);
+ }
+
+ #[test]
+ fn empty() { check_encoding(b""); }
+
+ #[test]
+ fn single() { check_encoding(b"*"); }
+
+ #[test]
+ fn two() { check_encoding(b"*x"); }
+
+ #[test]
+ fn just_below_boundary() { check_encoding(&[42; 512]); }
+
+ #[test]
+ fn just_above_boundary() { check_encoding(&[42; 513]); }
+
+ #[test]
+ fn just_above_double_boundary() { check_encoding(&[42; 1025]); }
+
+ #[test]
+ fn fmt_exact_macro() {
+ use crate::alloc::string::ToString;
+
+ struct Dummy([u8; 32]);
+
+ impl fmt::Display for Dummy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt_hex_exact!(f, 32, &self.0, Case::Lower)
+ }
+ }
+ let dummy = Dummy([42; 32]);
+ assert_eq!(dummy.to_string(), "2a".repeat(32));
+ assert_eq!(format!("{:.10}", dummy), "2a".repeat(5));
+ }
+
+ #[test]
+ fn display_short_with_padding() {
+ let v = vec![0xbe, 0xef];
+ assert_eq!(format!("Hello {:<8}!", v.as_hex()), "Hello beef !");
+ assert_eq!(format!("Hello {:-<8}!", v.as_hex()), "Hello beef----!");
+ assert_eq!(format!("Hello {:^8}!", v.as_hex()), "Hello beef !");
+ assert_eq!(format!("Hello {:>8}!", v.as_hex()), "Hello beef!");
+ }
+
+ #[test]
+ fn display_long() {
+ // Note this string is shorter than the one above.
+ let v = vec![0xab; 512];
+ let mut want = "0".repeat(2000 - 1024);
+ want.extend(core::iter::repeat("ab").take(512));
+ let got = format!("{:0>2000}", v.as_hex());
+ assert_eq!(got, want)
+ }
+
+ // Precision and padding act the same as for strings in the stdlib (because we use `Formatter::pad`).
+
+ #[test]
+ fn precision_truncates() {
+ // Precision gets the most significant bytes.
+ let v = vec![0x12, 0x34, 0x56, 0x78];
+ // Remember the integer is number of hex chars not number of bytes.
+ assert_eq!(format!("{0:.4}", v.as_hex()), "1234");
+ }
+
+ #[test]
+ fn precision_with_padding_truncates() {
+ // Precision gets the most significant bytes.
+ let v = vec![0x12, 0x34, 0x56, 0x78];
+ assert_eq!(format!("{0:10.4}", v.as_hex()), "1234 ");
+ }
+
+ #[test]
+ fn precision_with_padding_pads_right() {
+ let v = vec![0x12, 0x34, 0x56, 0x78];
+ assert_eq!(format!("{0:10.20}", v.as_hex()), "12345678 ");
+ }
+
+ #[test]
+ fn precision_with_padding_pads_left() {
+ let v = vec![0x12, 0x34, 0x56, 0x78];
+ assert_eq!(format!("{0:>10.20}", v.as_hex()), " 12345678");
+ }
+
+ #[test]
+ fn precision_with_padding_pads_center() {
+ let v = vec![0x12, 0x34, 0x56, 0x78];
+ assert_eq!(format!("{0:^10.20}", v.as_hex()), " 12345678 ");
+ }
+
+ #[test]
+ fn precision_with_padding_pads_center_odd() {
+ let v = vec![0x12, 0x34, 0x56, 0x78];
+ assert_eq!(format!("{0:^11.20}", v.as_hex()), " 12345678 ");
+ }
+
+ #[test]
+ fn precision_does_not_extend() {
+ let v = vec![0x12, 0x34, 0x56, 0x78];
+ assert_eq!(format!("{0:.16}", v.as_hex()), "12345678");
+ }
+
+ #[test]
+ fn padding_extends() {
+ let v = vec![0xab; 2];
+ assert_eq!(format!("{:0>8}", v.as_hex()), "0000abab");
+ }
+
+ #[test]
+ fn padding_does_not_truncate() {
+ let v = vec![0x12, 0x34, 0x56, 0x78];
+ assert_eq!(format!("{:0>4}", v.as_hex()), "12345678");
+ }
+
+ #[test]
+ fn hex_fmt_impl_macro_forward() {
+ struct Wrapper([u8; 4]);
+
+ impl Borrow<[u8]> for Wrapper {
+ fn borrow(&self) -> &[u8] { &self.0[..] }
+ }
+
+ impl_fmt_traits! {
+ #[display_backward(false)]
+ impl fmt_traits for Wrapper {
+ const LENGTH: usize = 4;
+ }
+ }
+
+ let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
+
+ let want = "12345678";
+ let got = format!("{}", tc);
+ assert_eq!(got, want);
+ }
+
+ #[test]
+ fn hex_fmt_impl_macro_backwards() {
+ struct Wrapper([u8; 4]);
+
+ impl Borrow<[u8]> for Wrapper {
+ fn borrow(&self) -> &[u8] { &self.0[..] }
+ }
+
+ impl_fmt_traits! {
+ #[display_backward(true)]
+ impl fmt_traits for Wrapper {
+ const LENGTH: usize = 4;
+ }
+ }
+
+ let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
+
+ let want = "78563412";
+ let got = format!("{}", tc);
+ assert_eq!(got, want);
+ }
+
+ #[test]
+ fn hex_fmt_impl_macro_gen_forward() {
+ struct Wrapper<T>([u8; 4], PhantomData<T>);
+
+ impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
+ fn borrow(&self) -> &[u8] { &self.0[..] }
+ }
+
+ impl_fmt_traits! {
+ #[display_backward(false)]
+ impl<T: Clone> fmt_traits for Wrapper<T> {
+ const LENGTH: usize = 4;
+ }
+ }
+
+ // We just use `u32` here as some arbitrary type that implements some arbitrary trait.
+ let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
+
+ let want = "12345678";
+ let got = format!("{}", tc);
+ assert_eq!(got, want);
+ }
+
+ #[test]
+ fn hex_fmt_impl_macro_gen_backwards() {
+ struct Wrapper<T>([u8; 4], PhantomData<T>);
+
+ impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
+ fn borrow(&self) -> &[u8] { &self.0[..] }
+ }
+
+ impl_fmt_traits! {
+ #[display_backward(true)]
+ impl<T: Clone> fmt_traits for Wrapper<T> {
+ const LENGTH: usize = 4;
+ }
+ }
+
+ // We just use `u32` here as some arbitrary type that implements some arbitrary trait.
+ let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
+
+ let want = "78563412";
+ let got = format!("{}", tc);
+ assert_eq!(got, want);
+ }
+ }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/src/error.rs b/external/vendor/hex-conservative-0.2.1/src/error.rs
new file mode 100644
index 0000000..8b85a2e
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/src/error.rs
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Error code for the `hex-conservative` crate.
+
+use core::fmt;
+
+use crate::write_err;
+
+/// Formats error.
+///
+/// If `std` feature is OFF appends error source (delimited by `: `). We do this because
+/// `e.source()` is only available in std builds, without this macro the error source is lost for
+/// no-std builds.
+#[macro_export]
+macro_rules! write_err {
+ ($writer:expr, $string:literal $(, $args:expr)*; $source:expr) => {
+ {
+ #[cfg(feature = "std")]
+ {
+ let _ = &$source; // Prevents clippy warnings.
+ write!($writer, $string $(, $args)*)
+ }
+ #[cfg(not(feature = "std"))]
+ {
+ write!($writer, concat!($string, ": {}") $(, $args)*, $source)
+ }
+ }
+ }
+}
+
+/// Hex decoding error.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum HexToBytesError {
+ /// Non-hexadecimal character.
+ InvalidChar(InvalidCharError),
+ /// Purported hex string had odd length.
+ OddLengthString(OddLengthStringError),
+}
+
+impl fmt::Display for HexToBytesError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use HexToBytesError::*;
+
+ match *self {
+ InvalidChar(ref e) => write_err!(f, "invalid char, failed to create bytes from hex"; e),
+ OddLengthString(ref e) =>
+ write_err!(f, "odd length, failed to create bytes from hex"; e),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for HexToBytesError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ use HexToBytesError::*;
+
+ match *self {
+ InvalidChar(ref e) => Some(e),
+ OddLengthString(ref e) => Some(e),
+ }
+ }
+}
+
+impl From<InvalidCharError> for HexToBytesError {
+ #[inline]
+ fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
+}
+
+impl From<OddLengthStringError> for HexToBytesError {
+ #[inline]
+ fn from(e: OddLengthStringError) -> Self { Self::OddLengthString(e) }
+}
+
+/// Invalid hex character.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct InvalidCharError {
+ pub(crate) invalid: u8,
+}
+
+impl InvalidCharError {
+ /// Returns the invalid character byte.
+ pub fn invalid_char(&self) -> u8 { self.invalid }
+}
+
+impl fmt::Display for InvalidCharError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "invalid hex char {}", self.invalid)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for InvalidCharError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
+}
+
+/// Purported hex string had odd length.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct OddLengthStringError {
+ pub(crate) len: usize,
+}
+
+impl OddLengthStringError {
+ /// Returns the odd length of the input string.
+ pub fn length(&self) -> usize { self.len }
+}
+
+impl fmt::Display for OddLengthStringError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "odd hex string length {}", self.len)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for OddLengthStringError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
+}
+
+/// Hex decoding error.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum HexToArrayError {
+ /// Non-hexadecimal character.
+ InvalidChar(InvalidCharError),
+ /// Tried to parse fixed-length hash from a string with the wrong length.
+ InvalidLength(InvalidLengthError),
+}
+
+impl fmt::Display for HexToArrayError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use HexToArrayError::*;
+
+ match *self {
+ InvalidChar(ref e) => crate::write_err!(f, "failed to parse hex digit"; e),
+ InvalidLength(ref e) => write_err!(f, "failed to parse hex"; e),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for HexToArrayError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ use HexToArrayError::*;
+
+ match *self {
+ InvalidChar(ref e) => Some(e),
+ InvalidLength(ref e) => Some(e),
+ }
+ }
+}
+
+impl From<InvalidCharError> for HexToArrayError {
+ #[inline]
+ fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
+}
+
+impl From<InvalidLengthError> for HexToArrayError {
+ #[inline]
+ fn from(e: InvalidLengthError) -> Self { Self::InvalidLength(e) }
+}
+
+/// Tried to parse fixed-length hash from a string with the wrong length.
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[non_exhaustive]
+pub struct InvalidLengthError {
+ /// The expected length.
+ pub expected: usize,
+ /// The invalid length.
+ pub invalid: usize,
+}
+
+impl fmt::Display for InvalidLengthError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "invilad hex string length {} (expected {})", self.invalid, self.expected)
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for InvalidLengthError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/src/iter.rs b/external/vendor/hex-conservative-0.2.1/src/iter.rs
new file mode 100644
index 0000000..d1798b0
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/src/iter.rs
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Iterator that converts hex to bytes.
+
+use core::convert::TryInto;
+use core::iter::FusedIterator;
+use core::str;
+#[cfg(feature = "std")]
+use std::io;
+
+#[cfg(all(feature = "core2", not(feature = "std")))]
+use core2::io;
+
+use crate::error::{InvalidCharError, OddLengthStringError};
+
+/// Convenience alias for `HexToBytesIter<HexDigitsIter<'a>>`.
+pub type HexSliceToBytesIter<'a> = HexToBytesIter<HexDigitsIter<'a>>;
+
+/// Iterator yielding bytes decoded from an iterator of pairs of hex digits.
+pub struct HexToBytesIter<T: Iterator<Item = [u8; 2]>> {
+ iter: T,
+}
+
+impl<'a> HexToBytesIter<HexDigitsIter<'a>> {
+ /// Constructs a new `HexToBytesIter` from a string slice.
+ ///
+ /// # Errors
+ ///
+ /// If the input string is of odd length.
+ #[inline]
+ pub fn new(s: &'a str) -> Result<Self, OddLengthStringError> {
+ if s.len() % 2 != 0 {
+ Err(OddLengthStringError { len: s.len() })
+ } else {
+ Ok(Self::new_unchecked(s))
+ }
+ }
+
+ pub(crate) fn new_unchecked(s: &'a str) -> Self {
+ Self::from_pairs(HexDigitsIter::new_unchecked(s.as_bytes()))
+ }
+}
+
+impl<T: Iterator<Item = [u8; 2]>> HexToBytesIter<T> {
+ /// Constructs a custom hex decoding iterator from another iterator.
+ #[inline]
+ pub fn from_pairs(iter: T) -> Self { Self { iter } }
+}
+
+impl<T: Iterator<Item = [u8; 2]>> Iterator for HexToBytesIter<T> {
+ type Item = Result<u8, InvalidCharError>;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ let [hi, lo] = self.iter.next()?;
+ Some(hex_chars_to_byte(hi, lo))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (min, max) = self.iter.size_hint();
+ (min / 2, max.map(|x| x / 2))
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ let [hi, lo] = self.iter.nth(n)?;
+ Some(hex_chars_to_byte(hi, lo))
+ }
+}
+
+impl<T: Iterator<Item = [u8; 2]> + DoubleEndedIterator> DoubleEndedIterator for HexToBytesIter<T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ let [hi, lo] = self.iter.next_back()?;
+ Some(hex_chars_to_byte(hi, lo))
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let [hi, lo] = self.iter.nth_back(n)?;
+ Some(hex_chars_to_byte(hi, lo))
+ }
+}
+
+impl<T: Iterator<Item = [u8; 2]> + ExactSizeIterator> ExactSizeIterator for HexToBytesIter<T> {}
+
+impl<T: Iterator<Item = [u8; 2]> + FusedIterator> FusedIterator for HexToBytesIter<T> {}
+
+#[cfg(any(feature = "std", feature = "core2"))]
+impl<T: Iterator<Item = [u8; 2]> + FusedIterator> io::Read for HexToBytesIter<T> {
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let mut bytes_read = 0usize;
+ for dst in buf {
+ match self.next() {
+ Some(Ok(src)) => {
+ *dst = src;
+ bytes_read += 1;
+ }
+ _ => break,
+ }
+ }
+ Ok(bytes_read)
+ }
+}
+
+/// An internal iterator returning hex digits from a string.
+///
+/// Generally you shouldn't need to refer to this or bother with it and just use
+/// [`HexToBytesIter::new`] consuming the returned value and use `HexSliceToBytesIter` if you need
+/// to refer to the iterator in your types.
+pub struct HexDigitsIter<'a> {
+ // Invariant: the length of the chunks is 2.
+ // Technically, this is `iter::Map` but we can't use it because fn is anonymous.
+ // We can swap this for actual `ArrayChunks` once it's stable.
+ iter: core::slice::ChunksExact<'a, u8>,
+}
+
+impl<'a> HexDigitsIter<'a> {
+ #[inline]
+ fn new_unchecked(digits: &'a [u8]) -> Self { Self { iter: digits.chunks_exact(2) } }
+}
+
+impl<'a> Iterator for HexDigitsIter<'a> {
+ type Item = [u8; 2];
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ self.iter.nth(n).map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
+ }
+}
+
+impl<'a> DoubleEndedIterator for HexDigitsIter<'a> {
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.iter.next_back().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ self.iter.nth_back(n).map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
+ }
+}
+
+impl<'a> ExactSizeIterator for HexDigitsIter<'a> {}
+
+impl<'a> core::iter::FusedIterator for HexDigitsIter<'a> {}
+
+/// `hi` and `lo` are bytes representing hex characters.
+fn hex_chars_to_byte(hi: u8, lo: u8) -> Result<u8, InvalidCharError> {
+ let hih = (hi as char).to_digit(16).ok_or(InvalidCharError { invalid: hi })?;
+ let loh = (lo as char).to_digit(16).ok_or(InvalidCharError { invalid: lo })?;
+
+ let ret = (hih << 4) + loh;
+ Ok(ret as u8)
+}
+
+/// Iterator over bytes which encodes the bytes and yields hex characters.
+pub struct BytesToHexIter<I: Iterator<Item = u8>> {
+ /// The iterator whose next byte will be encoded to yield hex characters.
+ iter: I,
+ /// The low character of the pair (high, low) of hex characters encoded per byte.
+ low: Option<char>,
+}
+
+impl<I> BytesToHexIter<I>
+where
+ I: Iterator<Item = u8>,
+{
+ /// Constructs a new `BytesToHexIter` from a byte iterator.
+ pub fn new(iter: I) -> BytesToHexIter<I> { Self { iter, low: None } }
+}
+
+impl<I> Iterator for BytesToHexIter<I>
+where
+ I: Iterator<Item = u8>,
+{
+ type Item = char;
+
+ #[inline]
+ fn next(&mut self) -> Option<char> {
+ match self.low {
+ Some(c) => {
+ self.low = None;
+ Some(c)
+ }
+ None => self.iter.next().map(|b| {
+ let (high, low) = byte_to_hex_chars(b);
+ self.low = Some(low);
+ high
+ }),
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (min, max) = self.iter.size_hint();
+ match self.low {
+ Some(_) => (min * 2 + 1, max.map(|max| max * 2 + 1)),
+ None => (min * 2, max.map(|max| max * 2)),
+ }
+ }
+}
+
+impl<I> DoubleEndedIterator for BytesToHexIter<I>
+where
+ I: DoubleEndedIterator + Iterator<Item = u8>,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<char> {
+ match self.low {
+ Some(c) => {
+ self.low = None;
+ Some(c)
+ }
+ None => self.iter.next_back().map(|b| {
+ let (high, low) = byte_to_hex_chars(b);
+ self.low = Some(low);
+ high
+ }),
+ }
+ }
+}
+
+impl<I> ExactSizeIterator for BytesToHexIter<I>
+where
+ I: ExactSizeIterator + Iterator<Item = u8>,
+{
+ #[inline]
+ fn len(&self) -> usize { self.iter.len() * 2 }
+}
+
+impl<I> FusedIterator for BytesToHexIter<I> where I: FusedIterator + Iterator<Item = u8> {}
+
+/// Returns the (high, low) hex characters encoding `b`.
+fn byte_to_hex_chars(b: u8) -> (char, char) {
+ const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
+
+ let high = HEX_TABLE[usize::from(b >> 4)];
+ let low = HEX_TABLE[usize::from(b & 0b00001111)];
+
+ (char::from(high), char::from(low))
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn encode_byte() {
+ let tcs =
+ vec![(0x00, ('0', '0')), (0x0a, ('0', 'a')), (0xad, ('a', 'd')), (0xff, ('f', 'f'))];
+ for (b, (high, low)) in tcs {
+ assert_eq!(byte_to_hex_chars(b), (high, low));
+ }
+ assert_eq!(byte_to_hex_chars(0x00), ('0', '0'));
+ assert_eq!(byte_to_hex_chars(0x0a), ('0', 'a'));
+ assert_eq!(byte_to_hex_chars(0xad), ('a', 'd'));
+ assert_eq!(byte_to_hex_chars(0xff), ('f', 'f'));
+ }
+
+ #[test]
+ fn decode_iter_forward() {
+ let hex = "deadbeef";
+ let bytes = [0xde, 0xad, 0xbe, 0xef];
+
+ for (i, b) in HexToBytesIter::new(hex).unwrap().enumerate() {
+ assert_eq!(b.unwrap(), bytes[i]);
+ }
+ }
+
+ #[test]
+ fn decode_iter_backward() {
+ let hex = "deadbeef";
+ let bytes = [0xef, 0xbe, 0xad, 0xde];
+
+ for (i, b) in HexToBytesIter::new(hex).unwrap().rev().enumerate() {
+ assert_eq!(b.unwrap(), bytes[i]);
+ }
+ }
+
+ #[test]
+ fn encode_iter() {
+ let bytes = [0xde, 0xad, 0xbe, 0xef];
+ let hex = "deadbeef";
+
+ for (i, c) in BytesToHexIter::new(bytes.iter().cloned()).enumerate() {
+ assert_eq!(c, hex.chars().nth(i).unwrap());
+ }
+ }
+
+ #[test]
+ fn encode_iter_backwards() {
+ let bytes = [0xde, 0xad, 0xbe, 0xef];
+ let hex = "efbeadde";
+
+ for (i, c) in BytesToHexIter::new(bytes.iter().cloned()).rev().enumerate() {
+ assert_eq!(c, hex.chars().nth(i).unwrap());
+ }
+ }
+
+ #[test]
+ fn roundtrip_forward() {
+ let hex = "deadbeefcafebabe";
+ let bytes_iter = HexToBytesIter::new(hex).unwrap().map(|res| res.unwrap());
+ let got = BytesToHexIter::new(bytes_iter).collect::<String>();
+ assert_eq!(got, hex);
+ }
+
+ #[test]
+ fn roundtrip_backward() {
+ let hex = "deadbeefcafebabe";
+ let bytes_iter = HexToBytesIter::new(hex).unwrap().rev().map(|res| res.unwrap());
+ let got = BytesToHexIter::new(bytes_iter).rev().collect::<String>();
+ assert_eq!(got, hex);
+ }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/src/lib.rs b/external/vendor/hex-conservative-0.2.1/src/lib.rs
new file mode 100644
index 0000000..4939821
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/src/lib.rs
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Hex encoding and decoding.
+//!
+//! General purpose hex encoding/decoding library with a conservative MSRV and dependency policy.
+//!
+//! ## Basic Usage
+//! ```
+//! # #[cfg(feature = "alloc")] {
+//! // In your manifest use the `package` key to improve import ergonomics.
+//! // hex = { package = "hex-conservative", version = "*" }
+//! # use hex_conservative as hex; // No need for this if using `package` as above.
+//! use hex::prelude::*;
+//!
+//! // Decode an arbitrary length hex string into a vector.
+//! let v = Vec::from_hex("deadbeef").expect("valid hex digits");
+//! // Or a known length hex string into a fixed size array.
+//! let a = <[u8; 4]>::from_hex("deadbeef").expect("valid length and valid hex digits");
+//!
+//! // We support `LowerHex` and `UpperHex` out of the box for `[u8]` slices.
+//! println!("An array as lower hex: {:x}", a.as_hex());
+//! // And for vecs since `Vec` derefs to byte slice.
+//! println!("A vector as upper hex: {:X}", v.as_hex());
+//!
+//! // Allocate a new string (also `to_upper_hex_string`).
+//! let s = v.to_lower_hex_string();
+//!
+//! // Please note, mixed case strings will still parse successfully but we only
+//! // support displaying hex in a single case.
+//! assert_eq!(
+//! Vec::from_hex("dEaDbEeF").expect("valid mixed case hex digits"),
+//! Vec::from_hex("deadbeef").expect("valid hex digits"),
+//! );
+//! # }
+//! ```
+
+#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
+// Experimental features we need.
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
+// Coding conventions
+#![warn(missing_docs)]
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+
+#[doc(hidden)]
+pub mod _export {
+ /// A re-export of core::*
+ pub mod _core {
+ pub use core::*;
+ }
+}
+
+pub mod buf_encoder;
+pub mod display;
+pub mod error;
+mod iter;
+pub mod parse;
+#[cfg(feature = "serde")]
+pub mod serde;
+
+/// Re-exports of the common crate traits.
+pub mod prelude {
+ #[doc(inline)]
+ pub use crate::{display::DisplayHex, parse::FromHex};
+}
+
+pub(crate) use table::Table;
+
+#[rustfmt::skip] // Keep public re-exports separate.
+#[doc(inline)]
+pub use self::{
+ display::DisplayHex,
+ error::{OddLengthStringError, HexToBytesError, HexToArrayError, InvalidCharError},
+ iter::{BytesToHexIter, HexToBytesIter, HexSliceToBytesIter},
+ parse::FromHex,
+};
+
+/// Possible case of hex.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub enum Case {
+ /// Produce lower-case chars (`[0-9a-f]`).
+ ///
+ /// This is the default.
+ Lower,
+
+ /// Produce upper-case chars (`[0-9A-F]`).
+ Upper,
+}
+
+impl Default for Case {
+ #[inline]
+ fn default() -> Self { Case::Lower }
+}
+
+impl Case {
+ /// Returns the encoding table.
+ ///
+ /// The returned table may only contain displayable ASCII chars.
+ #[inline]
+ #[rustfmt::skip]
+ pub(crate) fn table(self) -> &'static Table {
+ match self {
+ Case::Lower => &Table::LOWER,
+ Case::Upper => &Table::UPPER,
+ }
+ }
+}
+
+/// Correctness boundary for `Table`.
+mod table {
+ use arrayvec::ArrayString;
+
+ /// Table of hex chars.
+ //
+ // Correctness invariant: each byte in the table must be ASCII.
+ pub(crate) struct Table([u8; 16]);
+
+ impl Table {
+ pub(crate) const LOWER: Self = Table([
+ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd',
+ b'e', b'f',
+ ]);
+ pub(crate) const UPPER: Self = Table([
+ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D',
+ b'E', b'F',
+ ]);
+
+ /// Encodes single byte as two ASCII chars using the given table.
+ ///
+ /// The function guarantees only returning values from the provided table.
+ #[inline]
+ pub(crate) fn byte_to_hex(&self, byte: u8) -> ArrayString<2> {
+ let left = self.0[usize::from(byte.wrapping_shr(4))];
+ let right = self.0[usize::from(byte & 0x0F)];
+
+ ArrayString::from_byte_string(&[left, right]).expect("Table only contains valid ASCII")
+ }
+ }
+}
+
+/// Quick and dirty macro for parsing hex in tests.
+///
+/// For improved ergonomics import with: `use hex_conservative::test_hex_unwrap as hex;`
+#[macro_export]
+macro_rules! test_hex_unwrap (($hex:expr) => (<Vec<u8> as $crate::FromHex>::from_hex($hex).unwrap()));
+
+#[cfg(test)]
+mod tests {
+ use crate::test_hex_unwrap as hex;
+
+ #[test]
+ fn parse_hex_into_vector() {
+ let got = hex!("deadbeef");
+ let want = vec![0xde, 0xad, 0xbe, 0xef];
+ assert_eq!(got, want)
+ }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/src/parse.rs b/external/vendor/hex-conservative-0.2.1/src/parse.rs
new file mode 100644
index 0000000..fe8e98d
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/src/parse.rs
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: CC0-1.0
+
+//! Hex encoding and decoding.
+
+use core::{fmt, str};
+
+use arrayvec::ArrayVec;
+
+#[cfg(all(feature = "alloc", not(feature = "std")))]
+use crate::alloc::vec::Vec;
+use crate::error::InvalidLengthError;
+use crate::iter::HexToBytesIter;
+
+#[rustfmt::skip] // Keep public re-exports separate.
+pub use crate::error::{HexToBytesError, HexToArrayError};
+
+/// Trait for objects that can be deserialized from hex strings.
+pub trait FromHex: Sized {
+ /// Error type returned while parsing hex string.
+ type Error: Sized + fmt::Debug + fmt::Display;
+
+ /// Produces an object from a hex string.
+ fn from_hex(s: &str) -> Result<Self, Self::Error>;
+}
+
+#[cfg(any(test, feature = "std", feature = "alloc"))]
+impl FromHex for Vec<u8> {
+ type Error = HexToBytesError;
+
+ fn from_hex(s: &str) -> Result<Self, Self::Error> {
+ HexToBytesIter::new(s)?.map(|result| result.map_err(Into::into)).collect()
+ }
+}
+
+impl<const LEN: usize> FromHex for [u8; LEN] {
+ type Error = HexToArrayError;
+
+ fn from_hex(s: &str) -> Result<Self, Self::Error> {
+ if s.len() == LEN * 2 {
+ let mut ret = ArrayVec::<u8, LEN>::new();
+ // checked above
+ for byte in HexToBytesIter::new_unchecked(s) {
+ ret.push(byte?);
+ }
+ Ok(ret.into_inner().expect("inner is full"))
+ } else {
+ Err(InvalidLengthError { invalid: s.len(), expected: 2 * LEN }.into())
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::display::DisplayHex;
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ fn hex_error() {
+ use crate::error::{InvalidCharError, OddLengthStringError};
+
+ let oddlen = "0123456789abcdef0";
+ let badchar1 = "Z123456789abcdef";
+ let badchar2 = "012Y456789abcdeb";
+ let badchar3 = "«23456789abcdef";
+
+ assert_eq!(Vec::<u8>::from_hex(oddlen), Err(OddLengthStringError { len: 17 }.into()));
+ assert_eq!(
+ <[u8; 4]>::from_hex(oddlen),
+ Err(InvalidLengthError { invalid: 17, expected: 8 }.into())
+ );
+ assert_eq!(Vec::<u8>::from_hex(badchar1), Err(InvalidCharError { invalid: b'Z' }.into()));
+ assert_eq!(Vec::<u8>::from_hex(badchar2), Err(InvalidCharError { invalid: b'Y' }.into()));
+ assert_eq!(Vec::<u8>::from_hex(badchar3), Err(InvalidCharError { invalid: 194 }.into()));
+ }
+
+ #[test]
+ fn hex_to_array() {
+ let len_sixteen = "0123456789abcdef";
+ assert!(<[u8; 8]>::from_hex(len_sixteen).is_ok());
+ }
+
+ #[test]
+ fn hex_to_array_error() {
+ let len_sixteen = "0123456789abcdef";
+ assert_eq!(
+ <[u8; 4]>::from_hex(len_sixteen),
+ Err(InvalidLengthError { invalid: 16, expected: 8 }.into())
+ )
+ }
+
+ #[test]
+ fn mixed_case() {
+ let s = "DEADbeef0123";
+ let want_lower = "deadbeef0123";
+ let want_upper = "DEADBEEF0123";
+
+ let v = Vec::<u8>::from_hex(s).expect("valid hex");
+ assert_eq!(format!("{:x}", v.as_hex()), want_lower);
+ assert_eq!(format!("{:X}", v.as_hex()), want_upper);
+ }
+}
diff --git a/external/vendor/hex-conservative-0.2.1/src/serde.rs b/external/vendor/hex-conservative-0.2.1/src/serde.rs
new file mode 100644
index 0000000..c157de6
--- /dev/null
+++ b/external/vendor/hex-conservative-0.2.1/src/serde.rs
@@ -0,0 +1,108 @@
+//! Hex encoding with `serde`.
+//!
+//! The functions in this module de/serialize as hex _only_ when the serializer is human readable.
+//!
+//! # Examples
+//!
+//! ```
+//! # #[cfg(feature = "std")] {
+//! use hex_conservative as hex;
+//! use serde::{Serialize, Deserialize};
+//!
+//! #[derive(Debug, Serialize, Deserialize)]
+//! struct Foo {
+//! #[serde(with = "hex::serde")]
+//! bar: Vec<u8>,
+//! }
+//! # }
+//! ```
+
+use core::fmt;
+use core::marker::PhantomData;
+
+use serde::de::{Error, Visitor};
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+
+use crate::prelude::*;
+
+/// Serializes `data` as a hex string using lowercase characters.
+///
+/// We only serialize as hex if the serializer is human readable, if not we call through to the
+/// `Serialize` implementation for `data`.
+pub fn serialize<S, T>(data: T, s: S) -> Result<S::Ok, S::Error>
+where
+ S: Serializer,
+ T: Serialize + DisplayHex,
+{
+ serialize_lower(data, s)
+}
+
+/// Serializes `data` as a hex string using lowercase characters.
+///
+/// We only serialize as hex if the serializer is human readable, if not we call through to the
+/// `Serialize` implementation for `data`.
+pub fn serialize_lower<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
+where
+ S: Serializer,
+ T: Serialize + DisplayHex,
+{
+ // Don't do anything special when not human readable.
+ if !serializer.is_human_readable() {
+ serde::Serialize::serialize(&data, serializer)
+ } else {
+ serializer.collect_str(&format_args!("{:x}", data.as_hex()))
+ }
+}
+
+/// Serializes `data` as hex string using uppercase characters.
+///
+/// We only serialize as hex if the serializer is human readable, if not we call through to the
+/// `Serialize` implementation for `data`.
+pub fn serialize_upper<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
+where
+ S: Serializer,
+ T: Serialize + DisplayHex,
+{
+ // Don't do anything special when not human readable.
+ if !serializer.is_human_readable() {
+ serde::Serialize::serialize(&data, serializer)
+ } else {
+ serializer.collect_str(&format_args!("{:X}", data.as_hex()))
+ }
+}
+
+/// Deserializes a hex string into raw bytes.
+///
+/// Allows upper, lower, and mixed case characters (e.g. `a5b3c1`, `A5B3C1` and `A5b3C1`).
+///
+/// We only deserialize from hex if the serializer is human readable, if not we call through to the
+/// `Deserialize` implementation for `T`.
+pub fn deserialize<'de, D, T>(d: D) -> Result<T, D::Error>
+where
+ D: Deserializer<'de>,
+ T: Deserialize<'de> + FromHex,
+{
+ struct HexVisitor<T>(PhantomData<T>);
+
+ impl<'de, T> Visitor<'de> for HexVisitor<T>
+ where
+ T: FromHex,
+ {
+ type Value = T;
+
+ fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str("an ASCII hex string")
+ }
+
+ fn visit_str<E: Error>(self, data: &str) -> Result<Self::Value, E> {
+ FromHex::from_hex(data).map_err(Error::custom)
+ }
+ }
+
+ // Don't do anything special when not human readable.
+ if !d.is_human_readable() {
+ serde::Deserialize::deserialize(d)
+ } else {
+ d.deserialize_map(HexVisitor(PhantomData))
+ }
+}
diff --git a/external/vendor/hex-conservative/.cargo-checksum.json b/external/vendor/hex-conservative/.cargo-checksum.json
index c276490..e3f1fff 100644
--- a/external/vendor/hex-conservative/.cargo-checksum.json
+++ b/external/vendor/hex-conservative/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{".cargo_vcs_info.json":"5b405520bd52759ac7430bfcbe6cbc30ca6402ecf0c6790894b8013a0ac33307",".github/workflows/fuzz.yml":"20b24076bc0689a1214547fd08f5eaf553771b820f67d901ff337f95317c19fb",".github/workflows/rust.yaml":"a5c6877eef2b75354e2bd5034eb3c27f61fbf0b389b04ebc3cf261f3e67394e7","CHANGELOG.md":"f8ff29ff61d3ea0bb2886e300b96dc9535f78462ea9d14e864ac2949fbc0a829","Cargo.lock":"f7cc7fb347ec7aa2598b16933473f9a10e8ab679b28495e7f49c2fb6f3660e2d","Cargo.toml":"edce910166ffadc7557c3ec7b55e1a310d4b5bb38fa857ae151eaac272455c42","Cargo.toml.orig":"2c803d731510733c0c07330b11d7a7aaf1f3dad9da4ec8f7f40447511e72bc86","LICENSE":"7179683e8000e6bdc9bbc60d85edf0a4ac8e76f951857f54fcb775d5886f1309","README.md":"59b0b986e0b3f53e0f646ba8c0c64d75a6d9c93e04b02298b534a856c5285b82","clippy.toml":"89cd5d45d34652463cedfae1ac5fc2602f80e4d99688772f94a80bdeead90ed1","examples/custom.rs":"677ff623158a0936c7d749d78960b7de1d7742cbaab495fdd064f255932bbb9a","examples/hexy.rs":"faf50eab5ff947dc6a0f270439fdd8508b2b6ab49e893edd696e7ff08ecea830","examples/serde.rs":"6490d1c39bfc2886b9eae1b84a7bf969cf110d1003e97ada783158b287bc8255","examples/wrap_array_display_hex_trait.rs":"25c46bf17402cba1d2b7f71a95dea691eb8555c50157df13c8e7f225ad2a4985","examples/wrap_array_fmt_traits.rs":"2be6e7d357fcbb0e7865f323dbb463fb0ddfeca97fb62f10a1557f01d9312d33","githooks/pre-commit":"897530f773ae0000a25a994119ded74dd7e6fe01eeb7438f09e751bb00ce0943","rustfmt.toml":"52a5a471073587e9f58aab6a235adbc7eb8bed44bcbb5295827613bdac91c495","src/buf_encoder.rs":"f1ab77c9b9dbb7e3b02537de364514f401e63d8133b9f0bdf8d43760651d3418","src/display.rs":"1a12a731812c2ba3b0747ee457d4b9dc19e602e951f18e8c7b57db62d2c4ea3b","src/error.rs":"a529179b4aab2a213be11d21de1b8fc072d53ae1f60f05cf6a8c242a2558dd06","src/iter.rs":"ad7b94786411cb246f827a30fe851b64bb53aed1bc03f062af7d83a16e1c6823","src/lib.rs":"82a1a55df6fdddadbab21996429d30d3f10254fa4a5a2a9aa8bb176b28f79ce8","src/parse.rs":"f4926b553136c628b06d4224a9e04b54b7ae7273a4ebdad1f2fbfbea7134b533","src/serde.rs":"e5846390c871cda61714cb3f6a1d20aec0c2d0457930c277b2dd30e288c6b019"},"package":"5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"20f3e8a77e1b600e3e3272e0775ea9bc97e5d268c848eaeddf25237c72c91efc","CONTRIBUTING.md":"0d29e6874e7bc6db25a27dab4bbd552bdc72a4905b31ec75c4c2c91a6f0b8873","Cargo-minimal.lock":"d70f5a9b9f1508f0a3849d0ffecc16d1f1af1640c478590a1795f7e6d0ae7c89","Cargo-recent.lock":"d70f5a9b9f1508f0a3849d0ffecc16d1f1af1640c478590a1795f7e6d0ae7c89","Cargo.lock":"d70f5a9b9f1508f0a3849d0ffecc16d1f1af1640c478590a1795f7e6d0ae7c89","Cargo.toml":"d45078c773927eba8b69de399e6971479fe3f77103cfbe1211b33d2f067a0128","Cargo.toml.orig":"f72e8df550d34f0eefaf4feba72829f21724be1bbb65fa2a2f9480e6033fe5b2","LICENSE":"7179683e8000e6bdc9bbc60d85edf0a4ac8e76f951857f54fcb775d5886f1309","README.md":"3e00b66856a67255889873058fc0916395267b58ffc077c2b7352edc414fe8c8","justfile":"2c1598afa559de22388c0070c77327ebed97ddb2ca214f014e2258dad8962735","nightly-version":"3136d7a0cec5ac23bc2da00dae4597c862df89be56389f32fbe4563a106e2a14","rustfmt.toml":"123883259c8d4d75c13cef3b0e1ede038448eeacba3f45c809711094f3af0067","src/error.rs":"e9ad0d9509c47139d30a6b5f414b2379ddc283d643140eb5055dc84086f22522","src/iter.rs":"603e5fc253268e8ab98b7b6fdda933fd40788f82222e7406adbf5066efba5f45","src/lib.rs":"a33f502e018f8a3af5c637467b7d706d0f13de068ab8a310d1d8a98546b8c503"},"package":"366fa3443ac84474447710ec17bb00b05dfbd096137817981e86f992f21a2793"}
\ No newline at end of file
diff --git a/external/vendor/hex-conservative/.cargo_vcs_info.json b/external/vendor/hex-conservative/.cargo_vcs_info.json
deleted file mode 100644
index 9c47180..0000000
--- a/external/vendor/hex-conservative/.cargo_vcs_info.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "git": {
- "sha1": "405a7ebf615168436e6a76004bcb40accbd48f77"
- },
- "path_in_vcs": ""
-}
\ No newline at end of file
diff --git a/external/vendor/hex-conservative/.github/workflows/fuzz.yml b/external/vendor/hex-conservative/.github/workflows/fuzz.yml
deleted file mode 100644
index e64df35..0000000
--- a/external/vendor/hex-conservative/.github/workflows/fuzz.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-# Automatically generated by fuzz/generate-files.sh
-name: Fuzz
-
-on:
- push:
- branches:
- - master
- - 'test-ci/**'
- pull_request:
-
-jobs:
- fuzz:
- if: ${{ !github.event.act }}
- runs-on: ubuntu-20.04
- strategy:
- fail-fast: false
- matrix:
- fuzz_target: [
-hex,
-encode,
- ]
- steps:
- - name: Install test dependencies
- run: sudo apt-get update -y && sudo apt-get install -y binutils-dev libunwind8-dev libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc libiberty-dev
- - uses: actions/checkout@v2
- - uses: actions/cache@v2
- id: cache-fuzz
- with:
- path: |
- ~/.cargo/bin
- fuzz/target
- target
- key: cache-${{ matrix.target }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
- - uses: actions-rs/toolchain@v1
- with:
- toolchain: 1.58
- override: true
- profile: minimal
- - name: fuzz
- run: cd fuzz && ./fuzz.sh "${{ matrix.fuzz_target }}"
- - run: echo "${{ matrix.fuzz_target }}" >executed_${{ matrix.fuzz_target }}
- - uses: actions/upload-artifact@v2
- with:
- name: executed_${{ matrix.fuzz_target }}
- path: executed_${{ matrix.fuzz_target }}
-
- verify-execution:
- if: ${{ !github.event.act }}
- needs: fuzz
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - uses: actions/download-artifact@v2
- - name: Display structure of downloaded files
- run: ls -R
- - run: find executed_* -type f -exec cat {} + | sort > executed
- - run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed
diff --git a/external/vendor/hex-conservative/.github/workflows/rust.yaml b/external/vendor/hex-conservative/.github/workflows/rust.yaml
deleted file mode 100644
index 0c2698a..0000000
--- a/external/vendor/hex-conservative/.github/workflows/rust.yaml
+++ /dev/null
@@ -1,132 +0,0 @@
-on:
- push:
- branches:
- - master
- - 'test-ci/**'
- pull_request:
-
-name: Continuous integration
-
-jobs:
- Stable:
- name: Test - stable toolchain
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- steps:
- - name: Checkout Crate
- uses: actions/checkout@v3
- - name: Checkout Toolchain
- # https://github.com/dtolnay/rust-toolchain
- uses: dtolnay/rust-toolchain@stable
- - name: Running test script
- env:
- DO_DOCS: true
- DO_FEATURE_MATRIX: true
- run: ./contrib/test.sh
-
- Beta:
- name: Test - beta toolchain
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- steps:
- - name: Checkout Crate
- uses: actions/checkout@v3
- - name: Checkout Toolchain
- uses: dtolnay/rust-toolchain@beta
- - name: Running test script
- run: ./contrib/test.sh
-
- Nightly:
- name: Test - nightly toolchain
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- steps:
- - name: Checkout Crate
- uses: actions/checkout@v3
- - name: Checkout Toolchain
- uses: dtolnay/rust-toolchain@nightly
- - name: Running test script
- env:
- DO_DOCSRS: true
- run: ./contrib/test.sh
-
- MSRV:
- name: Test - 1.56.1 toolchain
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- steps:
- - name: Checkout Crate
- uses: actions/checkout@v3
- - name: Checkout Toolchain
- uses: dtolnay/rust-toolchain@1.56.1
- - name: Running test script
- env:
- DO_FEATURE_MATRIX: true
- run: ./contrib/test.sh
-
- Lint:
- name: Clippy - stable toolchain
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- steps:
- - name: Checkout Crate
- uses: actions/checkout@v3
- - name: Checkout Toolchain
- uses: dtolnay/rust-toolchain@stable
- - name: Running test script
- env:
- DO_LINT: true
- run: ./contrib/test.sh
-
- Fmt:
- name: Format - nightly toolchain
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- steps:
- - name: Checkout Crate
- uses: actions/checkout@v3
- - name: Checkout Toolchain
- uses: dtolnay/rust-toolchain@nightly
- - name: Running test script
- env:
- DO_FMT: true
- run: ./contrib/test.sh
-
- Arch32bit:
- name: Test 32-bit version
- runs-on: ubuntu-latest
- steps:
- - name: Checkout Crate
- uses: actions/checkout@v3
- - name: Checkout Toolchain
- uses: dtolnay/rust-toolchain@stable
- - name: Add architecture i386
- run: sudo dpkg --add-architecture i386
- - name: Install i686 gcc
- run: sudo apt-get update -y && sudo apt-get install -y gcc-multilib
- - name: Install target
- run: rustup target add i686-unknown-linux-gnu
- - name: Run test on i686
- run: cargo test --target i686-unknown-linux-gnu
-
- Cross:
- name: Cross test
- if: ${{ !github.event.act }}
- runs-on: ubuntu-latest
- steps:
- - name: Checkout Crate
- uses: actions/checkout@v3
- - name: Checkout Toolchain
- uses: dtolnay/rust-toolchain@stable
- - name: Install target
- run: rustup target add s390x-unknown-linux-gnu
- - name: install cross
- run: cargo install cross --locked
- - name: run cross test
- run: cross test --target s390x-unknown-linux-gnu
diff --git a/external/vendor/hex-conservative/CHANGELOG.md b/external/vendor/hex-conservative/CHANGELOG.md
index 7c08513..acfddba 100644
--- a/external/vendor/hex-conservative/CHANGELOG.md
+++ b/external/vendor/hex-conservative/CHANGELOG.md
@@ -1,3 +1,45 @@
+# 1.0.1 - 2025-12-02
+
+- Remove `doc_auto_cfg`
+
+# 1.0.0 - 2025-07-11
+
+- Removed niche reexports from root
+- Various documentation improvements
+- A few test improvements
+
+# 1.0.0 release candidate 2 -- 2025-06-27
+
+- Removed iterator API that got published by accident
+
+# 1.0.0 release candidate 1 -- 2025-05-16
+
+- Exports `decode_to_array`, `decode_to_vec`, and all error types.
+
+The goal of this release is to enable library authors to use hex-conservative,
+exposing error types from this library in their own APIs, and not need to worry
+that they will face API breakage because of this.
+
+Future minor releases will add encoding support and a more expansive set of traits.
+
+# 0.3.0 - 2024-09-18
+
+- Re-implement `HexWriter` [#113](https://github.com/rust-bitcoin/hex-conservative/pull/113)
+- Fix `Display` width and precision of `DisplayByteSlice` [#114](https://github.com/rust-bitcoin/hex-conservative/pull/114)
+- Encoding performance improvements [#117](https://github.com/rust-bitcoin/hex-conservative/pull/117)
+- Relax bounds of `BytesToHexIter` [#118](https://github.com/rust-bitcoin/hex-conservative/pull/118)
+- Add case to `BytesToHexIter` [#120](https://github.com/rust-bitcoin/hex-conservative/pull/120)
+- Encapsulate unsafe code inside the table module [#121](https://github.com/rust-bitcoin/hex-conservative/pull/121)
+- Fix `HexToBytesIter::size_hint` [#122](https://github.com/rust-bitcoin/hex-conservative/pull/122)
+- Restrict `BufEncoder` to uniform case encoding [#119](https://github.com/rust-bitcoin/hex-conservative/pull/119)
+- Remove the `core2` dependency [#105](https://github.com/rust-bitcoin/hex-conservative/pull/105)
+- Introduce more serde utilities [#92](https://github.com/rust-bitcoin/hex-conservative/pull/92)
+- Add `impl_fmt_traits` macro [#90](https://github.com/rust-bitcoin/hex-conservative/pull/90)
+- Enable serialization of byte slices [#96](https://github.com/rust-bitcoin/hex-conservative/pull/96)
+- Bump MSRV to Rust `1.63.0` [#102](https://github.com/rust-bitcoin/hex-conservative/pull/102)
+- Store position of invalid char in `InvalidCharError` [#107](https://github.com/rust-bitcoin/hex-conservative/pull/107)
+- Only encode the bytes formatted in the hex string [#108](https://github.com/rust-bitcoin/hex-conservative/pull/108)
+
# 0.2.1 - 2024-05-17
- Add a new `impl_fmt_traits` macro that can be used to implement `fmt::{LowerHex, UpperHex,
@@ -27,6 +69,10 @@ There are a bunch of breaking changes in this release, including:
- Hide error internal [#44](https://github.com/rust-bitcoin/hex-conservative/pull/44)
- Return specific error from `HexToByesIter::new` [#62](https://github.com/rust-bitcoin/hex-conservative/pull/62)
+# 0.1.2 - 2024-05-14
+
+- Fix bug in output of `InvalidError` [#88](https://github.com/rust-bitcoin/hex-conservative/pull/88).
+
# 0.1.1 - 2023-07-19
- [Add `test_hex_unwrap`](https://github.com/rust-bitcoin/hex-conservative/pull/24) hex parsing macro for test usage.
diff --git a/external/vendor/hex-conservative/CONTRIBUTING.md b/external/vendor/hex-conservative/CONTRIBUTING.md
new file mode 100644
index 0000000..256b13d
--- /dev/null
+++ b/external/vendor/hex-conservative/CONTRIBUTING.md
@@ -0,0 +1,33 @@
+# Contributing to hex-conservative
+
+Thanks for the interest in contributing!
+Before you do anything, please familiarize yourself with the stabilization strategy as described in the README, since it places some restrictions on how the code is developed.
+
+## Contributing to the stable crate
+
+Generally, you should try to make your contributions against the `master` branch which contains unstable code and thus it's much more forgiving when it comes to adding any new features.
+However it may be sometimes impossible, in which case please follow these rules:
+
+1. Breaking any API of the 1.0 crate is unacceptable unless it can be done with semver trick (e.g. feature modifictaions). Please do not even attempt to do this.
+2. For new APIs, please gate all of them behing `#[cfg(hex-conservative-unstable)]` to ensure they won't get used by accident. The stabilization procedure is similar to that of Rust itself.
+3. Once a new unstable API is released, try using it in a real project. (Ideally multiple different projects.)
+4. If you want to get an unstable feature stabilized, write a stabilization report that contains at least one Open Source project that uses it and a summary of how well the feature works in practice.
+5. Any new feature should be out for at least 6 months before stabilization to give projects enough chance to test it out. We may make exceptions for particularly simple and desirable features.
+
+## General rules
+
+First and formost, all code has to produce correct results and have API that models a domain accurately and makes it hard to do wrong things.
+If any other rule is in conflict with the first rule, the first rule takes precedence.
+Both encoding and decoding should be reasonably fast. Please avoid unneeded allocations or other kinds of code that cause slowness.
+All code should be idiomatic, reasonably consistent and maintainable. This includes high importance of "single source of truth" because violating it is extremely prone to causing bugs.
+
+## Githooks
+
+To assist devs in catching errors _before_ running CI we provide some githooks. If you do not
+already have locally configured githooks you can use the ones in this repository by running, in the
+root directory of the repository:
+```
+git config --local core.hooksPath githooks/
+```
+
+Alternatively add symlinks in your `.git/hooks` directory to any of the githooks we provide.
diff --git a/external/vendor/hex-conservative/Cargo-minimal.lock b/external/vendor/hex-conservative/Cargo-minimal.lock
new file mode 100644
index 0000000..0ac901e
--- /dev/null
+++ b/external/vendor/hex-conservative/Cargo-minimal.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "hex-conservative"
+version = "1.0.1"
+dependencies = [
+ "if_rust_version",
+]
+
+[[package]]
+name = "if_rust_version"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46dbcb333e86939721589d25a3557e180b52778cb33c7fdfe9e0158ff790d5ec"
diff --git a/external/vendor/hex-conservative/Cargo-recent.lock b/external/vendor/hex-conservative/Cargo-recent.lock
new file mode 100644
index 0000000..0ac901e
--- /dev/null
+++ b/external/vendor/hex-conservative/Cargo-recent.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "hex-conservative"
+version = "1.0.1"
+dependencies = [
+ "if_rust_version",
+]
+
+[[package]]
+name = "if_rust_version"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46dbcb333e86939721589d25a3557e180b52778cb33c7fdfe9e0158ff790d5ec"
diff --git a/external/vendor/hex-conservative/Cargo.lock b/external/vendor/hex-conservative/Cargo.lock
index cf61369..0ac901e 100644
--- a/external/vendor/hex-conservative/Cargo.lock
+++ b/external/vendor/hex-conservative/Cargo.lock
@@ -2,111 +2,15 @@
# It is not intended for manual editing.
version = 3
-[[package]]
-name = "arrayvec"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
-
-[[package]]
-name = "core2"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cf12d2dad3ed124aa116f59561428478993d69ab81ae4d30e5349c9c5b5a5f6"
-dependencies = [
- "memchr",
-]
-
[[package]]
name = "hex-conservative"
-version = "0.2.1"
-dependencies = [
- "arrayvec",
- "core2",
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
-
-[[package]]
-name = "memchr"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.83"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
-
-[[package]]
-name = "serde"
-version = "1.0.202"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.202"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.117"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
-dependencies = [
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.65"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
+version = "1.0.1"
dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
+ "if_rust_version",
]
[[package]]
-name = "unicode-ident"
-version = "1.0.12"
+name = "if_rust_version"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "46dbcb333e86939721589d25a3557e180b52778cb33c7fdfe9e0158ff790d5ec"
diff --git a/external/vendor/hex-conservative/Cargo.toml b/external/vendor/hex-conservative/Cargo.toml
index dd9d6f5..7e31921 100644
--- a/external/vendor/hex-conservative/Cargo.toml
+++ b/external/vendor/hex-conservative/Cargo.toml
@@ -10,19 +10,25 @@
# See Cargo.toml.orig for the original contents.
[package]
-edition = "2018"
+edition = "2021"
+rust-version = "1.63.0"
name = "hex-conservative"
-version = "0.2.1"
+version = "1.0.1"
authors = [
"Martin Habovštiak <martin.habovstiak@gmail.com>",
"Andrew Poelstra <apoelstra@wpsoftware.net>",
]
+build = false
exclude = [
"tests",
"contrib",
]
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
description = "A hex encoding and decoding crate with a conservative MSRV and dependency policy."
-documentation = "https://docs.rs/hex-conservative/"
readme = "README.md"
keywords = [
"encoding",
@@ -40,47 +46,144 @@ rustdoc-args = [
"docsrs",
]
-[[example]]
-name = "hexy"
-
-[[example]]
-name = "custom"
-
-[[example]]
-name = "wrap_array_display_hex_trait"
-
-[[example]]
-name = "wrap_array_fmt_traits"
-
-[[example]]
-name = "serde"
-required-features = [
- "std",
- "serde",
-]
-
-[dependencies.arrayvec]
-version = "0.7.2"
-default-features = false
+[features]
+alloc = []
+default = ["std"]
+newer-rust-version = ["dep:if_rust_version"]
+std = ["alloc"]
-[dependencies.core2]
-version = "0.3.2"
-optional = true
-default-features = false
+[lib]
+name = "hex_conservative"
+path = "src/lib.rs"
-[dependencies.serde]
-version = "1.0"
+[dependencies.if_rust_version]
+version = "1.0.0"
optional = true
-default-features = false
-
-[dev-dependencies.serde]
-version = "1.0"
-features = ["derive"]
-[dev-dependencies.serde_json]
-version = "1.0"
+[dev-dependencies]
-[features]
-alloc = []
-default = ["std"]
-std = ["alloc"]
+[lints.clippy]
+assigning_clones = "warn"
+bool_to_int_with_if = "warn"
+borrow_as_ptr = "warn"
+case_sensitive_file_extension_comparisons = "warn"
+cast_lossless = "warn"
+cast_possible_truncation = "allow"
+cast_possible_wrap = "allow"
+cast_precision_loss = "warn"
+cast_ptr_alignment = "warn"
+cast_sign_loss = "allow"
+checked_conversions = "warn"
+cloned_instead_of_copied = "warn"
+copy_iterator = "warn"
+default_trait_access = "warn"
+doc_link_with_quotes = "warn"
+doc_markdown = "warn"
+empty_enum = "warn"
+enum_glob_use = "warn"
+expl_impl_clone_on_copy = "warn"
+explicit_deref_methods = "warn"
+explicit_into_iter_loop = "warn"
+explicit_iter_loop = "warn"
+filter_map_next = "warn"
+flat_map_option = "warn"
+float_cmp = "warn"
+fn_params_excessive_bools = "warn"
+from_iter_instead_of_collect = "warn"
+if_not_else = "warn"
+ignored_unit_patterns = "warn"
+implicit_clone = "warn"
+implicit_hasher = "warn"
+inconsistent_struct_constructor = "warn"
+index_refutable_slice = "warn"
+inefficient_to_string = "warn"
+inline_always = "warn"
+into_iter_without_iter = "warn"
+invalid_upcast_comparisons = "warn"
+items_after_statements = "warn"
+iter_filter_is_ok = "warn"
+iter_filter_is_some = "warn"
+iter_not_returning_iterator = "warn"
+iter_without_into_iter = "warn"
+large_digit_groups = "warn"
+large_futures = "warn"
+large_stack_arrays = "warn"
+large_types_passed_by_value = "warn"
+linkedlist = "warn"
+macro_use_imports = "warn"
+manual_assert = "warn"
+manual_instant_elapsed = "warn"
+manual_is_power_of_two = "warn"
+manual_is_variant_and = "warn"
+manual_let_else = "warn"
+manual_ok_or = "warn"
+manual_range_contains = "allow"
+manual_string_new = "warn"
+many_single_char_names = "warn"
+map_unwrap_or = "warn"
+match_bool = "allow"
+match_on_vec_items = "warn"
+match_same_arms = "allow"
+match_wild_err_arm = "warn"
+match_wildcard_for_single_variants = "warn"
+maybe_infinite_iter = "warn"
+mismatching_type_param_order = "warn"
+missing_errors_doc = "warn"
+missing_fields_in_debug = "warn"
+missing_panics_doc = "warn"
+must_use_candidate = "allow"
+mut_mut = "warn"
+naive_bytecount = "warn"
+needless_bitwise_bool = "warn"
+needless_continue = "warn"
+needless_for_each = "warn"
+needless_pass_by_value = "warn"
+needless_question_mark = "allow"
+needless_raw_string_hashes = "warn"
+no_effect_underscore_binding = "warn"
+no_mangle_with_rust_abi = "warn"
+option_as_ref_cloned = "warn"
+option_option = "warn"
+ptr_as_ptr = "warn"
+ptr_cast_constness = "warn"
+pub_underscore_fields = "warn"
+range_minus_one = "warn"
+range_plus_one = "warn"
+redundant_closure_for_method_calls = "warn"
+redundant_else = "warn"
+ref_as_ptr = "warn"
+ref_binding_to_reference = "warn"
+ref_option = "warn"
+ref_option_ref = "warn"
+return_self_not_must_use = "warn"
+same_functions_in_if_condition = "warn"
+semicolon_if_nothing_returned = "warn"
+should_panic_without_expect = "warn"
+similar_names = "allow"
+single_char_pattern = "warn"
+single_match_else = "warn"
+stable_sort_primitive = "warn"
+str_split_at_newline = "warn"
+string_add_assign = "warn"
+struct_excessive_bools = "warn"
+struct_field_names = "warn"
+too_many_lines = "warn"
+transmute_ptr_to_ptr = "warn"
+trivially_copy_pass_by_ref = "warn"
+unchecked_duration_subtraction = "warn"
+unicode_not_nfc = "warn"
+uninlined_format_args = "allow"
+unnecessary_box_returns = "warn"
+unnecessary_join = "warn"
+unnecessary_literal_bound = "warn"
+unnecessary_wraps = "warn"
+unnested_or_patterns = "warn"
+unreadable_literal = "warn"
+unsafe_derive_deserialize = "warn"
+unused_async = "warn"
+unused_self = "warn"
+used_underscore_binding = "warn"
+used_underscore_items = "warn"
+verbose_bit_mask = "warn"
+wildcard_imports = "warn"
+zero_sized_map_values = "warn"
diff --git a/external/vendor/hex-conservative/Cargo.toml.orig b/external/vendor/hex-conservative/Cargo.toml.orig
index 4bffbcd..3cc948b 100644
--- a/external/vendor/hex-conservative/Cargo.toml.orig
+++ b/external/vendor/hex-conservative/Cargo.toml.orig
@@ -1,51 +1,160 @@
[package]
name = "hex-conservative"
-version = "0.2.1"
+version = "1.0.1"
authors = ["Martin Habovštiak <martin.habovstiak@gmail.com>", "Andrew Poelstra <apoelstra@wpsoftware.net>"]
license = "CC0-1.0"
repository = "https://github.com/rust-bitcoin/hex-conservative"
-documentation = "https://docs.rs/hex-conservative/"
description = "A hex encoding and decoding crate with a conservative MSRV and dependency policy."
categories = ["encoding"]
keywords = ["encoding", "hex", "hexadecimal"]
readme = "README.md"
-edition = "2018"
+edition = "2021"
+rust-version = "1.63.0"
exclude = ["tests", "contrib"]
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
-[workspace]
-members = ["fuzz"]
-
[features]
default = ["std"]
std = ["alloc"]
alloc = []
+# Enables detection of newer rust versions to provide additional features
+# Turning it on may pull in dependencies that run build scripts and prolong compile time.
+# This feature will do nothing once our MSRV supports version detection natively and will
+# be removed using semver trick
+newer-rust-version = ["dep:if_rust_version"]
[dependencies]
-arrayvec = { version = "0.7.2", default-features = false }
-core2 = { version = "0.3.2", default-features = false, optional = true }
-serde = { version = "1.0", default-features = false, optional = true }
-
+if_rust_version = { version = "1.0.0", optional = true }
[dev-dependencies]
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-
-[[example]]
-name = "hexy"
-
-[[example]]
-name = "custom"
-
-[[example]]
-name = "wrap_array_display_hex_trait"
-
-[[example]]
-name = "wrap_array_fmt_traits"
-[[example]]
-name = "serde"
-required-features = ["std", "serde"]
+[lints.clippy]
+# Exclude lints we don't think are valuable.
+needless_question_mark = "allow" # https://github.com/rust-bitcoin/rust-bitcoin/pull/2134
+manual_range_contains = "allow" # More readable than clippy's format.
+# Exhaustive list of pedantic clippy lints
+assigning_clones = "warn"
+bool_to_int_with_if = "warn"
+borrow_as_ptr = "warn"
+case_sensitive_file_extension_comparisons = "warn"
+cast_lossless = "warn"
+cast_possible_truncation = "allow" # All casts should include a code comment (except test code).
+cast_possible_wrap = "allow" # Same as above re code comment.
+cast_precision_loss = "warn"
+cast_ptr_alignment = "warn"
+cast_sign_loss = "allow" # All casts should include a code comment (except in test code).
+checked_conversions = "warn"
+cloned_instead_of_copied = "warn"
+copy_iterator = "warn"
+default_trait_access = "warn"
+doc_link_with_quotes = "warn"
+doc_markdown = "warn"
+empty_enum = "warn"
+enum_glob_use = "warn"
+expl_impl_clone_on_copy = "warn"
+explicit_deref_methods = "warn"
+explicit_into_iter_loop = "warn"
+explicit_iter_loop = "warn"
+filter_map_next = "warn"
+flat_map_option = "warn"
+float_cmp = "warn"
+fn_params_excessive_bools = "warn"
+from_iter_instead_of_collect = "warn"
+if_not_else = "warn"
+ignored_unit_patterns = "warn"
+implicit_clone = "warn"
+implicit_hasher = "warn"
+inconsistent_struct_constructor = "warn"
+index_refutable_slice = "warn"
+inefficient_to_string = "warn"
+inline_always = "warn"
+into_iter_without_iter = "warn"
+invalid_upcast_comparisons = "warn"
+items_after_statements = "warn"
+iter_filter_is_ok = "warn"
+iter_filter_is_some = "warn"
+iter_not_returning_iterator = "warn"
+iter_without_into_iter = "warn"
+large_digit_groups = "warn"
+large_futures = "warn"
+large_stack_arrays = "warn"
+large_types_passed_by_value = "warn"
+linkedlist = "warn"
+macro_use_imports = "warn"
+manual_assert = "warn"
+manual_instant_elapsed = "warn"
+manual_is_power_of_two = "warn"
+manual_is_variant_and = "warn"
+manual_let_else = "warn"
+manual_ok_or = "warn"
+manual_string_new = "warn"
+many_single_char_names = "warn"
+map_unwrap_or = "warn"
+match_bool = "allow" # Adds extra indentation and LOC.
+match_on_vec_items = "warn"
+match_same_arms = "allow" # Collapses things that are conceptually unrelated to each other.
+match_wild_err_arm = "warn"
+match_wildcard_for_single_variants = "warn"
+maybe_infinite_iter = "warn"
+mismatching_type_param_order = "warn"
+missing_errors_doc = "warn"
+missing_fields_in_debug = "warn"
+missing_panics_doc = "warn"
+must_use_candidate = "allow" # Useful for audit but many false positives.
+mut_mut = "warn"
+naive_bytecount = "warn"
+needless_bitwise_bool = "warn"
+needless_continue = "warn"
+needless_for_each = "warn"
+needless_pass_by_value = "warn"
+needless_raw_string_hashes = "warn"
+no_effect_underscore_binding = "warn"
+no_mangle_with_rust_abi = "warn"
+option_as_ref_cloned = "warn"
+option_option = "warn"
+ptr_as_ptr = "warn"
+ptr_cast_constness = "warn"
+pub_underscore_fields = "warn"
+range_minus_one = "warn"
+range_plus_one = "warn"
+redundant_closure_for_method_calls = "warn"
+redundant_else = "warn"
+ref_as_ptr = "warn"
+ref_binding_to_reference = "warn"
+ref_option = "warn"
+ref_option_ref = "warn"
+return_self_not_must_use = "warn"
+same_functions_in_if_condition = "warn"
+semicolon_if_nothing_returned = "warn"
+should_panic_without_expect = "warn"
+similar_names = "allow" # Too many (subjectively) false positives.
+single_char_pattern = "warn"
+single_match_else = "warn"
+stable_sort_primitive = "warn"
+str_split_at_newline = "warn"
+string_add_assign = "warn"
+struct_excessive_bools = "warn"
+struct_field_names = "warn"
+too_many_lines = "warn"
+transmute_ptr_to_ptr = "warn"
+trivially_copy_pass_by_ref = "warn"
+unchecked_duration_subtraction = "warn"
+unicode_not_nfc = "warn"
+uninlined_format_args = "allow" # This is a subjective style choice.
+unnecessary_box_returns = "warn"
+unnecessary_join = "warn"
+unnecessary_literal_bound = "warn"
+unnecessary_wraps = "warn"
+unnested_or_patterns = "warn"
+unreadable_literal = "warn"
+unsafe_derive_deserialize = "warn"
+unused_async = "warn"
+unused_self = "warn"
+used_underscore_binding = "warn"
+used_underscore_items = "warn"
+verbose_bit_mask = "warn"
+wildcard_imports = "warn"
+zero_sized_map_values = "warn"
diff --git a/external/vendor/hex-conservative/README.md b/external/vendor/hex-conservative/README.md
index 546ef87..38ca88d 100644
--- a/external/vendor/hex-conservative/README.md
+++ b/external/vendor/hex-conservative/README.md
@@ -1,20 +1,46 @@
-# Bitcoin Hexadecimal Library
+# A Rust hexadecimal decoding library
General purpose hex encoding/decoding library with a conservative MSRV and dependency policy.
+**You're currently looking at the stable crate which has advanced features removed** to make
+stabilization quicker and thus allowing downstream crates to stabilize quicker too. To get the
+full feature set check the lower (0.x.y) versions. Read Stabilization strategy section for more
+information.
+
+## Stabilization strategy
+
+Because downstream crates may need to return hex errors in their APIs and they need to be
+stabilized soon, this crate only exposes the errors and two basic decoding functions. This
+should already help with the vast majority of the cases and we're sufficiently confident that
+these errors won't have a breaking change any time soon (possibly never).
+
+If you're writing a binary you don't need to worry about any of this and just use the unstable
+version for now. If you're writing a library you should use these stable errors in the API but
+you may internally depend on the unstable crate version to get the advanced features that won't
+affect your API. This way your API can stabilize before all features in this crate are fully
+stable and you still can use all of them.
+
+## Crate feature flags
+
+* `std` - enables the standard library, on by default.
+* `alloc` - enables features that require allocation such as decoding into `Vec<u8>`, implied
+by `std`.
+* `newer-rust-version` - enables Rust version detection and thus newer features, may add
+ dependency on a feature detection crate to reduce compile times. This
+ feature is expected to do nothing once the native detection is in Rust
+ and our MSRV is at least that version. We may also remove the feature
+ gate in 2.0 with semver trick once that happens.
+
## Minimum Supported Rust Version (MSRV)
-This library should compile with almost any combination of features on **Rust 1.56.1**, however we
+This library should compile with almost any combination of features on **Rust 1.63.0**, however we
reserve the right to use features to guard compiler specific code so `--all-features` may not work
using the MSRV toolchain.
-### Githooks
+### Policy
-To assist devs in catching errors _before_ running CI we provide some githooks. If you do not
-already have locally configured githooks you can use the ones in this repository by running, in the
-root directory of the repository:
-```
-git config --local core.hooksPath githooks/
-```
+We don't intend to bump MSRV until the newer Rust version is at least two years old and also
+included in Debian stable (1.63 is in Debian 12 at the moment).
-Alternatively add symlinks in your `.git/hooks` directory to any of the githooks we provide.
+Note though that the dependencies may have looser policy. This is not considered
+breaking/wrong - you would just need to pin them in `Cargo.lock` (not `.toml`).
diff --git a/external/vendor/hex-conservative/clippy.toml b/external/vendor/hex-conservative/clippy.toml
deleted file mode 100644
index 56ce04e..0000000
--- a/external/vendor/hex-conservative/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-msrv = "1.56.1"
diff --git a/external/vendor/hex-conservative/examples/custom.rs b/external/vendor/hex-conservative/examples/custom.rs
deleted file mode 100644
index 0fc77f1..0000000
--- a/external/vendor/hex-conservative/examples/custom.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-//! Demonstrate hexadecimal encoding and decoding for a type where hex is not the natural hex representation but the type can still be encoded/decoded to/from hex.
-//!
-//! For a type where hex is the natural representation see `./hexy.rs`.
-//! To wrap an array see the `./wrap_array_*` examples.
-
-use core::fmt;
-use core::str::FromStr;
-
-use hex_conservative::{DisplayHex, FromHex, HexToArrayError, HexToBytesError};
-
-fn main() {
- let s = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
- println!("Parse from hex: {}", s);
-
- let hexy = ALittleBitHexy::from_hex(s).expect("the correct number of valid hex digits");
- println!("Display ALittleBitHexy as string: {}", hexy);
- println!("Display ALittleBitHexy as a hex: {:x}", hexy.as_hex());
-
- #[cfg(feature = "alloc")]
- {
- let hex = hexy.to_lower_hex_string();
- let from_hex = ALittleBitHexy::from_hex(&hex).expect("failed to parse hex");
- assert_eq!(from_hex, hexy);
- }
-}
-
-/// A struct that displays using some application specific format but also supports printing as hex.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct ALittleBitHexy {
- // Some opaque data that should be printed as hex.
- data: [u8; 32],
- // Some other application data.
- x: usize,
-}
-
-impl ALittleBitHexy {
- /// Example constructor.
- pub fn new(x: usize) -> Self { Self { x, data: [0_u8; 32] } }
-}
-
-impl fmt::Debug for ALittleBitHexy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Formatter::debug_struct(f, "ALittleBitHexy")
- .field("data", &self.data.as_hex())
- .field("x", &self.x)
- .finish()
- }
-}
-
-/// `Display` uses some application specific format (and roundtrips with `FromStr`).
-impl fmt::Display for ALittleBitHexy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Some application specific format:{}", self.x)
- }
-}
-
-impl FromStr for ALittleBitHexy {
- type Err = Error;
- fn from_str(_: &str) -> Result<Self, Self::Err> {
- todo!("Parse a string as formatted by `Display`")
- }
-}
-
-// If the object can be parsed from hex, implement `FromHex`.
-
-impl FromHex for ALittleBitHexy {
- type Error = HexToArrayError;
-
- fn from_hex(s: &str) -> Result<Self, Self::Error> {
- // Errors if the input is invalid
- let data = <[u8; 32] as FromHex>::from_hex(s)?;
- // This is a contrived example (using x==0).
- Ok(ALittleBitHexy { data, x: 0 })
- }
-}
-
-// Implement conversion to hex by implementing `DisplayHex` on a wrapper type.
-
-impl<'a> DisplayHex for &'a ALittleBitHexy {
- type Display = DisplayALittleBitHexy<'a>;
-
- fn as_hex(self) -> Self::Display { DisplayALittleBitHexy { data: &self.data } }
-
- fn hex_reserve_suggestion(self) -> usize {
- self.data.len().checked_mul(2).expect("the string wouldn't fit into address space")
- }
-}
-
-/// Displays `ALittleBitHexy` as hex.
-///
-/// Created by [`<&ALittleBitHexy as DisplayHex>::as_hex`](DisplayHex::as_hex).
-pub struct DisplayALittleBitHexy<'a> {
- data: &'a [u8],
-}
-
-impl<'a> fmt::Display for DisplayALittleBitHexy<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
-}
-
-impl<'a> fmt::Debug for DisplayALittleBitHexy<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
-}
-
-impl<'a> fmt::LowerHex for DisplayALittleBitHexy<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::LowerHex::fmt(&self.data.as_hex(), f)
- }
-}
-
-impl<'a> fmt::UpperHex for DisplayALittleBitHexy<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::UpperHex::fmt(&self.data.as_hex(), f)
- }
-}
-
-/// Example Error.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum Error {
- /// Conversion error while parsing hex string.
- Conversion(HexToBytesError),
- /// Invalid string for array.
- Array(HexToArrayError),
- /// Attempt to parse invalid string.
- InvalidStringFormat,
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use Error::*;
-
- match *self {
- Conversion(ref e) => write!(f, "conversion error: {:?}", e),
- Array(ref e) => write!(f, "array error: {:?}", e),
- InvalidStringFormat => write!(f, "invalid string format"),
- }
- }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- use Error::*;
-
- match *self {
- Conversion(ref e) => Some(e),
- Array(ref e) => Some(e),
- InvalidStringFormat => None,
- }
- }
-}
-
-impl From<HexToBytesError> for Error {
- fn from(e: HexToBytesError) -> Self { Self::Conversion(e) }
-}
-
-impl From<HexToArrayError> for Error {
- fn from(e: HexToArrayError) -> Self { Self::Array(e) }
-}
diff --git a/external/vendor/hex-conservative/examples/hexy.rs b/external/vendor/hex-conservative/examples/hexy.rs
deleted file mode 100644
index 93f9ee4..0000000
--- a/external/vendor/hex-conservative/examples/hexy.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-//! Demonstrate hexadecimal encoding and decoding for a type with a natural hex representation.
-//!
-//! For a type where hex is supported but is not the natural representation see `./custom.rs`.
-//! To wrap an array see the `./wrap_array_*` examples.
-
-use std::fmt;
-use std::str::FromStr;
-
-use hex_conservative::{fmt_hex_exact, Case, DisplayHex, FromHex, HexToArrayError};
-
-fn main() {
- let s = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
- println!("Parse hex from string: {}", s);
-
- let hexy = Hexy::from_hex(s).expect("the correct number of valid hex digits");
- let display = format!("{}", hexy);
- println!("Display Hexy as string: {}", display);
-
- assert_eq!(display, s);
-}
-
-/// A struct that always uses hex when in string form.
-pub struct Hexy {
- // Some opaque data.
- data: [u8; 32],
-}
-
-impl Hexy {
- /// Demonstrates getting internal opaque data as a byte slice.
- pub fn as_bytes(&self) -> &[u8] { &self.data }
-}
-
-impl fmt::Debug for Hexy {
- fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- fmt::Formatter::debug_struct(f, "Hexy").field("data", &self.data.as_hex()).finish()
- }
-}
-
-// We implement `Display`/`FromStr` using `LowerHex`/`FromHex` respectively, if hex was not the
-// natural representation for this type this would not be the case.
-
-impl fmt::Display for Hexy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
-}
-
-impl FromStr for Hexy {
- type Err = HexToArrayError;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> { Hexy::from_hex(s) }
-}
-
-// Implement conversion to hex by first converting our type to a byte slice.
-
-impl fmt::LowerHex for Hexy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- // This is equivalent to but more performant than:
- // fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
- fmt_hex_exact!(f, 32, self.as_bytes(), Case::Lower)
- }
-}
-
-impl fmt::UpperHex for Hexy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- // This is equivalent to but more performant than:
- // fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
- fmt_hex_exact!(f, 32, self.as_bytes(), Case::Upper)
- }
-}
-
-// And use a fixed size array to convert from hex.
-
-impl FromHex for Hexy {
- type Error = HexToArrayError;
-
- fn from_hex(s: &str) -> Result<Self, Self::Error> {
- // Errors if the input is invalid
- let a = <[u8; 32] as FromHex>::from_hex(s)?;
- Ok(Hexy { data: a })
- }
-}
diff --git a/external/vendor/hex-conservative/examples/serde.rs b/external/vendor/hex-conservative/examples/serde.rs
deleted file mode 100644
index ad40974..0000000
--- a/external/vendor/hex-conservative/examples/serde.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-//! Demonstrate how to use the serde module with struct fields.
-
-#![allow(clippy::disallowed_names)] // Foo is a valid name.
-
-use hex_conservative as hex;
-use serde::{Deserialize, Serialize};
-
-/// Abstracts over foo.
-#[derive(Debug, Serialize, Deserialize)]
-pub struct Foo {
- // serialized as a hexadecimal string.
- #[serde(with = "hex::serde")]
- pub u: Vec<u8>,
- // serialized as an array of decimal integers.
- pub v: Vec<u8>,
-}
-
-fn main() {
- let v = vec![0xde, 0xad, 0xbe, 0xef];
-
- let foo = Foo { u: v.clone(), v };
- let ser = serde_json::to_string(&foo).expect("failed to serialize foo");
-
- // Prints:
- //
- // foo: {"u":"deadbeef","v":[222,173,190,239]}
- //
- println!("\nfoo: {}", ser);
-}
diff --git a/external/vendor/hex-conservative/examples/wrap_array_display_hex_trait.rs b/external/vendor/hex-conservative/examples/wrap_array_display_hex_trait.rs
deleted file mode 100644
index a635005..0000000
--- a/external/vendor/hex-conservative/examples/wrap_array_display_hex_trait.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-// SPDX-License-Identifier: CC0-1.0
-
-//! Hex encode/decode a type that wraps an array - using an implementation of the `DisplayHex` trait.
-//!
-//! For an example using the standard library `fmt` traits see `./wrap_array_fmt_traits.rs`.
-
-use hex_conservative::display::DisplayArray;
-use hex_conservative::{DisplayHex, FromHex, HexToArrayError};
-
-fn main() {
- let hex = "00000000cafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
- println!("\nParse from hex: {}\n", hex);
-
- let array = <[u8; 32] as FromHex>::from_hex(hex).expect("failed to parse array");
- let wrap = Wrap::from_hex(hex).expect("failed to parse wrapped array");
-
- println!("Print an array using traits from the standard libraries `fmt` module along with the provided implementation of `DisplayHex`:\n");
- println!("LowerHex: {:x}", array.as_hex());
- println!("UpperHex: {:X}", array.as_hex());
- println!("Display: {}", array.as_hex());
- println!("Debug: {:?}", array.as_hex());
- println!("Debug pretty: {:#?}", array.as_hex());
-
- println!("\n");
-
- println!(
- "Print the wrapped array directly using traits from the standard libraries `fmt` module:\n"
- );
- println!("LowerHex: {:x}", wrap.as_hex());
- println!("UpperHex: {:X}", wrap.as_hex());
- println!("Display: {}", wrap.as_hex());
- println!("Debug: {:?}", wrap.as_hex());
- println!("Debug pretty: {:#?}", wrap.as_hex());
-
- #[cfg(feature = "alloc")]
- {
- // We cannot call `to_string` on the wrapped type to allocate a string, if you wish to
- // use that trait method see `./wrap_array_fmt_traits.rs`.
- let array_hex = array.to_lower_hex_string();
- let wrap_hex = wrap.to_lower_hex_string();
- assert_eq!(array_hex, wrap_hex);
- }
-}
-
-pub struct Wrap([u8; 32]);
-
-impl FromHex for Wrap {
- type Error = HexToArrayError;
-
- fn from_hex(s: &str) -> Result<Self, Self::Error> { Ok(Self(FromHex::from_hex(s)?)) }
-}
-
-/// Use `DisplayArray` to display the `Wrap` type.
-///
-// TODO: The following statement is not true because `DislpayByteSlice` does not prefix pretty debug with 0x - fix this.
-/// Alternately use `DisplayByteSlice` which will achieve exactly the same thing.
-// impl<'a> DisplayHex for &'a Wrap {
-// type Display = DisplayByteSlice<'a>;
-// fn as_hex(self) -> Self::Display { self.0.as_ref().as_hex() }
-// fn hex_reserve_suggestion(self) -> usize { self.0.as_ref().hex_reserve_suggestion() }
-// }
-impl<'a> DisplayHex for &'a Wrap {
- type Display = DisplayArray<'a, 64>;
- fn as_hex(self) -> Self::Display { self.0.as_hex() }
- fn hex_reserve_suggestion(self) -> usize { 64 }
-}
diff --git a/external/vendor/hex-conservative/examples/wrap_array_fmt_traits.rs b/external/vendor/hex-conservative/examples/wrap_array_fmt_traits.rs
deleted file mode 100644
index 4d1fb2d..0000000
--- a/external/vendor/hex-conservative/examples/wrap_array_fmt_traits.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-// SPDX-License-Identifier: CC0-1.0
-
-//! Hex encode/decode a type that wraps an array - using implementations of the standard library
-//!
-//! `fmt` traits. For an example using the `DisplayHex` trait see `./wrap_array_display_hex.rs`.
-
-use core::fmt;
-use core::str::FromStr;
-
-use hex_conservative::{DisplayHex, FromHex, HexToArrayError};
-
-fn main() {
- let hex = "deadbeefcafebabedeadbeefcafebabedeadbeefcafebabedeadbeefcafebabe";
- println!("\nParse from hex: {}\n", hex);
-
- let array = <[u8; 32] as FromHex>::from_hex(hex).expect("failed to parse array");
- let wrap = Wrap::from_str(hex).expect("failed to parse wrapped array from hex string");
-
- println!("Print an array using traits from the standard libraries `fmt` module along with the provided implementation of `DisplayHex`:\n");
- println!("LowerHex: {:x}", array.as_hex());
- println!("UpperHex: {:X}", array.as_hex());
- println!("Display: {}", array.as_hex());
- println!("Debug: {:?}", array.as_hex());
- println!("Debug pretty: {:#?}", array.as_hex());
-
- println!("\n");
-
- println!(
- "Print the wrapped array directly using traits from the standard libraries `fmt` module:\n"
- );
- println!("LowerHex: {:x}", wrap);
- println!("UpperHex: {:X}", wrap);
- println!("Display: {}", wrap);
- println!("Debug: {:?}", wrap);
- println!("Debug pretty: {:#?}", wrap);
-
- // We cannot call `to_lower_hex_string` on the wrapped type to allocate a string, if you wish to
- // use that trait method see `./wrap_array_display_hex_trait.rs`.
- let array_hex = array.as_hex().to_string();
- let wrap_hex = wrap.to_string();
- assert_eq!(array_hex, wrap_hex);
-}
-
-pub struct Wrap([u8; 32]);
-
-impl fmt::Debug for Wrap {
- fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- fmt::Formatter::debug_tuple(f, "Wrap").field(&self.0.as_hex()).finish()
- }
-}
-
-impl fmt::Display for Wrap {
- fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- fmt::Display::fmt(&self.0.as_hex(), f)
- }
-}
-
-impl fmt::LowerHex for Wrap {
- fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- fmt::LowerHex::fmt(&self.0.as_hex(), f)
- }
-}
-
-impl fmt::UpperHex for Wrap {
- fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- fmt::LowerHex::fmt(&self.0.as_hex(), f)
- }
-}
-
-impl FromStr for Wrap {
- type Err = HexToArrayError;
- fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Self(FromHex::from_hex(s)?)) }
-}
diff --git a/external/vendor/hex-conservative/githooks/pre-commit b/external/vendor/hex-conservative/githooks/pre-commit
deleted file mode 100755
index 5bb2c48..0000000
--- a/external/vendor/hex-conservative/githooks/pre-commit
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/bin/sh
-#
-# Verify what is about to be committed. Called by "git commit" with no
-# arguments. The hook should exit with non-zero status after issuing an
-# appropriate message if it wants to stop the commit.
-
-if git rev-parse --verify HEAD >/dev/null 2>&1
-then
- against=HEAD
-else
- # Initial commit: diff against an empty tree object
- against=$(git hash-object -t tree /dev/null)
-fi
-
-# If you want to allow non-ASCII filenames set this variable to true.
-allownonascii=$(git config --bool hooks.allownonascii)
-
-# Redirect output to stderr.
-exec 1>&2
-
-# Cross platform projects tend to avoid non-ASCII filenames; prevent
-# them from being added to the repository. We exploit the fact that the
-# printable range starts at the space character and ends with tilde.
-if [ "$allownonascii" != "true" ] &&
- # Note that the use of brackets around a tr range is ok here, (it's
- # even required, for portability to Solaris 10's /usr/bin/tr), since
- # the square bracket bytes happen to fall in the designated range.
- test $(git diff --cached --name-only --diff-filter=A -z $against |
- LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
-then
- cat <<\EOF
-Error: Attempt to add a non-ASCII file name.
-
-This can cause problems if you want to work with people on other platforms.
-
-To be portable it is advisable to rename the file.
-
-If you know what you are doing you can disable this check using:
-
- git config hooks.allownonascii true
-EOF
- exit 1
-fi
-
-# If there are whitespace errors, print the offending file names and fail.
-git diff-index --check --cached $against -- || exit 1
-
-# Check that code lints cleanly.
-cargo clippy --all-features -- -D warnings || exit 1
-
-# Check that there are no formatting issues.
-cargo +nightly fmt --check || exit 1
diff --git a/external/vendor/hex-conservative/justfile b/external/vendor/hex-conservative/justfile
new file mode 100644
index 0000000..f5fd526
--- /dev/null
+++ b/external/vendor/hex-conservative/justfile
@@ -0,0 +1,30 @@
+default:
+ @just --list
+
+# Cargo build everything.
+build:
+ cargo build --workspace --all-targets --all-features
+
+# Cargo check everything.
+check:
+ cargo check --workspace --all-targets --all-features
+
+# Lint everything.
+lint:
+ cargo +$(cat ./nightly-version) clippy --workspace --all-targets --all-features -- --deny warnings
+
+# Run cargo fmt
+fmt:
+ cargo +$(cat ./nightly-version) fmt --all
+
+# Check the formatting
+format:
+ cargo +$(cat ./nightly-version) fmt --all --check
+
+# Generate documentation.
+docsrs *flags:
+ RUSTDOCFLAGS="--cfg docsrs -D warnings -D rustdoc::broken-intra-doc-links" cargo +$(cat ./nightly-version) doc --all-features {{flags}}
+
+# Update the recent and minimal lock files.
+update-lock-files:
+ contrib/update-lock-files.sh
diff --git a/external/vendor/hex-conservative/nightly-version b/external/vendor/hex-conservative/nightly-version
new file mode 100644
index 0000000..952e0e5
--- /dev/null
+++ b/external/vendor/hex-conservative/nightly-version
@@ -0,0 +1 @@
+nightly-2025-02-14
diff --git a/external/vendor/hex-conservative/rustfmt.toml b/external/vendor/hex-conservative/rustfmt.toml
index ab4989f..8b66ef0 100644
--- a/external/vendor/hex-conservative/rustfmt.toml
+++ b/external/vendor/hex-conservative/rustfmt.toml
@@ -71,7 +71,7 @@ color = "Auto"
unstable_features = false
disable_all_formatting = false
skip_children = false
-hide_parse_errors = false
+show_parse_errors = true
error_on_line_overflow = false
error_on_unformatted = false
emit_mode = "Files"
diff --git a/external/vendor/hex-conservative/src/buf_encoder.rs b/external/vendor/hex-conservative/src/buf_encoder.rs
deleted file mode 100644
index 0aa1802..0000000
--- a/external/vendor/hex-conservative/src/buf_encoder.rs
+++ /dev/null
@@ -1,244 +0,0 @@
-// SPDX-License-Identifier: CC0-1.0
-
-//! Implements a buffered encoder.
-//!
-//! This is a low-level module, most uses should be satisfied by the `display` module instead.
-//!
-//! The main type in this module is [`BufEncoder`] which provides buffered hex encoding.
-//! `BufEncoder` is faster than the usual `write!(f, "{02x}", b)?` in a for loop because it reduces
-//! dynamic dispatch and decreases the number of allocations if a `String` is being created.
-
-use core::borrow::Borrow;
-
-use arrayvec::ArrayString;
-
-use super::Case;
-
-/// Hex-encodes bytes into the provided buffer.
-///
-/// This is an important building block for fast hex-encoding. Because string writing tools
-/// provided by `core::fmt` involve dynamic dispatch and don't allow reserving capacity in strings
-/// buffering the hex and then formatting it is significantly faster.
-pub struct BufEncoder<const CAP: usize> {
- buf: ArrayString<CAP>,
-}
-
-impl<const CAP: usize> BufEncoder<CAP> {
- const _CHECK_EVEN_CAPACITY: () = [(); 1][CAP % 2];
-
- /// Creates an empty `BufEncoder`.
- #[inline]
- pub fn new() -> Self { BufEncoder { buf: ArrayString::new() } }
-
- /// Encodes `byte` as hex in given `case` and appends it to the buffer.
- ///
- /// ## Panics
- ///
- /// The method panics if the buffer is full.
- #[inline]
- #[track_caller]
- pub fn put_byte(&mut self, byte: u8, case: Case) {
- self.buf.push_str(&case.table().byte_to_hex(byte));
- }
-
- /// Encodes `bytes` as hex in given `case` and appends them to the buffer.
- ///
- /// ## Panics
- ///
- /// The method panics if the bytes wouldn't fit the buffer.
- #[inline]
- #[track_caller]
- pub fn put_bytes<I>(&mut self, bytes: I, case: Case)
- where
- I: IntoIterator,
- I::Item: Borrow<u8>,
- {
- self.put_bytes_inner(bytes.into_iter(), case)
- }
-
- #[inline]
- #[track_caller]
- fn put_bytes_inner<I>(&mut self, bytes: I, case: Case)
- where
- I: Iterator,
- I::Item: Borrow<u8>,
- {
- // May give the compiler better optimization opportunity
- if let Some(max) = bytes.size_hint().1 {
- assert!(max <= self.space_remaining());
- }
- for byte in bytes {
- self.put_byte(*byte.borrow(), case);
- }
- }
-
- /// Encodes as many `bytes` as fit into the buffer as hex and return the remainder.
- ///
- /// This method works just like `put_bytes` but instead of panicking it returns the unwritten
- /// bytes. The method returns an empty slice if all bytes were written
- #[must_use = "this may write only part of the input buffer"]
- #[inline]
- #[track_caller]
- pub fn put_bytes_min<'a>(&mut self, bytes: &'a [u8], case: Case) -> &'a [u8] {
- let to_write = self.space_remaining().min(bytes.len());
- self.put_bytes(&bytes[..to_write], case);
- &bytes[to_write..]
- }
-
- /// Returns true if no more bytes can be written into the buffer.
- #[inline]
- pub fn is_full(&self) -> bool { self.space_remaining() == 0 }
-
- /// Returns the written bytes as a hex `str`.
- #[inline]
- pub fn as_str(&self) -> &str { &self.buf }
-
- /// Resets the buffer to become empty.
- #[inline]
- pub fn clear(&mut self) { self.buf.clear(); }
-
- /// How many bytes can be written to this buffer.
- ///
- /// Note that this returns the number of bytes before encoding, not number of hex digits.
- #[inline]
- pub fn space_remaining(&self) -> usize { self.buf.remaining_capacity() / 2 }
-
- pub(crate) fn put_filler(&mut self, filler: char, max_count: usize) -> usize {
- let mut buf = [0; 4];
- let filler = filler.encode_utf8(&mut buf);
- let max_capacity = self.buf.remaining_capacity() / filler.len();
- let to_write = max_capacity.min(max_count);
-
- for _ in 0..to_write {
- self.buf.push_str(filler);
- }
-
- to_write
- }
-}
-
-impl<const CAP: usize> Default for BufEncoder<CAP> {
- fn default() -> Self { Self::new() }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn empty() {
- let encoder = BufEncoder::<2>::new();
- assert_eq!(encoder.as_str(), "");
- assert!(!encoder.is_full());
- }
-
- #[test]
- fn single_byte_exact_buf() {
- let mut encoder = BufEncoder::<2>::new();
- assert_eq!(encoder.space_remaining(), 1);
- encoder.put_byte(42, Case::Lower);
- assert_eq!(encoder.as_str(), "2a");
- assert_eq!(encoder.space_remaining(), 0);
- assert!(encoder.is_full());
- encoder.clear();
- assert_eq!(encoder.space_remaining(), 1);
- assert!(!encoder.is_full());
- encoder.put_byte(42, Case::Upper);
- assert_eq!(encoder.as_str(), "2A");
- assert_eq!(encoder.space_remaining(), 0);
- assert!(encoder.is_full());
- }
-
- #[test]
- fn single_byte_oversized_buf() {
- let mut encoder = BufEncoder::<4>::new();
- assert_eq!(encoder.space_remaining(), 2);
- encoder.put_byte(42, Case::Lower);
- assert_eq!(encoder.space_remaining(), 1);
- assert_eq!(encoder.as_str(), "2a");
- assert!(!encoder.is_full());
- encoder.clear();
- assert_eq!(encoder.space_remaining(), 2);
- encoder.put_byte(42, Case::Upper);
- assert_eq!(encoder.as_str(), "2A");
- assert_eq!(encoder.space_remaining(), 1);
- assert!(!encoder.is_full());
- }
-
- #[test]
- fn two_bytes() {
- let mut encoder = BufEncoder::<4>::new();
- encoder.put_byte(42, Case::Lower);
- assert_eq!(encoder.space_remaining(), 1);
- encoder.put_byte(255, Case::Lower);
- assert_eq!(encoder.space_remaining(), 0);
- assert_eq!(encoder.as_str(), "2aff");
- assert!(encoder.is_full());
- encoder.clear();
- assert!(!encoder.is_full());
- encoder.put_byte(42, Case::Upper);
- encoder.put_byte(255, Case::Upper);
- assert_eq!(encoder.as_str(), "2AFF");
- assert!(encoder.is_full());
- }
-
- #[test]
- fn put_bytes_min() {
- let mut encoder = BufEncoder::<2>::new();
- let remainder = encoder.put_bytes_min(b"", Case::Lower);
- assert_eq!(remainder, b"");
- assert_eq!(encoder.as_str(), "");
- let remainder = encoder.put_bytes_min(b"*", Case::Lower);
- assert_eq!(remainder, b"");
- assert_eq!(encoder.as_str(), "2a");
- encoder.clear();
- let remainder = encoder.put_bytes_min(&[42, 255], Case::Lower);
- assert_eq!(remainder, &[255]);
- assert_eq!(encoder.as_str(), "2a");
- }
-
- #[test]
- fn same_as_fmt() {
- use core::fmt::{self, Write};
-
- struct Writer {
- buf: [u8; 2],
- pos: usize,
- }
-
- impl Writer {
- fn as_str(&self) -> &str { core::str::from_utf8(&self.buf[..self.pos]).unwrap() }
- }
-
- impl Write for Writer {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- assert!(self.pos <= 2);
- if s.len() > 2 - self.pos {
- Err(fmt::Error)
- } else {
- self.buf[self.pos..(self.pos + s.len())].copy_from_slice(s.as_bytes());
- self.pos += s.len();
- Ok(())
- }
- }
- }
-
- let mut writer = Writer { buf: [0u8; 2], pos: 0 };
- let mut encoder = BufEncoder::<2>::new();
-
- for i in 0..=255 {
- write!(writer, "{:02x}", i).unwrap();
- encoder.put_byte(i, Case::Lower);
- assert_eq!(encoder.as_str(), writer.as_str());
- writer.pos = 0;
- encoder.clear();
- }
- for i in 0..=255 {
- write!(writer, "{:02X}", i).unwrap();
- encoder.put_byte(i, Case::Upper);
- assert_eq!(encoder.as_str(), writer.as_str());
- writer.pos = 0;
- encoder.clear();
- }
- }
-}
diff --git a/external/vendor/hex-conservative/src/display.rs b/external/vendor/hex-conservative/src/display.rs
deleted file mode 100644
index 8818660..0000000
--- a/external/vendor/hex-conservative/src/display.rs
+++ /dev/null
@@ -1,760 +0,0 @@
-// SPDX-License-Identifier: CC0-1.0
-
-//! Helpers for displaying bytes as hex strings.
-//!
-//! This module provides a trait for displaying things as hex as well as an implementation for
-//! `&[u8]`.
-//!
-//! For arrays and slices we support padding and precision for length < 512 bytes.
-//!
-//! # Examples
-//!
-//! ```
-//! use hex_conservative::DisplayHex;
-//!
-//! // Display as hex.
-//! let v = vec![0xde, 0xad, 0xbe, 0xef];
-//! assert_eq!(format!("{}", v.as_hex()), "deadbeef");
-//!
-//! // Get the most significant bytes.
-//! let v = vec![0x01, 0x23, 0x45, 0x67];
-//! assert_eq!(format!("{0:.4}", v.as_hex()), "0123");
-//!
-//! // Padding with zeros
-//! let v = vec![0xab; 2];
-//! assert_eq!(format!("{:0>8}", v.as_hex()), "0000abab");
-//!```
-
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-use core::borrow::Borrow;
-use core::fmt;
-
-use super::Case;
-use crate::buf_encoder::BufEncoder;
-
-/// Extension trait for types that can be displayed as hex.
-///
-/// Types that have a single, obvious text representation being hex should **not** implement this
-/// trait and simply implement `Display` instead.
-///
-/// This trait should be generally implemented for references only. We would prefer to use GAT but
-/// that is beyond our MSRV. As a lint we require the `IsRef` trait which is implemented for all
-/// references.
-pub trait DisplayHex: Copy + sealed::IsRef {
- /// The type providing [`fmt::Display`] implementation.
- ///
- /// This is usually a wrapper type holding a reference to `Self`.
- type Display: fmt::Display + fmt::Debug + fmt::LowerHex + fmt::UpperHex;
-
- /// Display `Self` as a continuous sequence of ASCII hex chars.
- fn as_hex(self) -> Self::Display;
-
- /// Create a lower-hex-encoded string.
- ///
- /// A shorthand for `to_hex_string(Case::Lower)`, so that `Case` doesn't need to be imported.
- ///
- /// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
- #[cfg(feature = "alloc")]
- fn to_lower_hex_string(self) -> String { self.to_hex_string(Case::Lower) }
-
- /// Create an upper-hex-encoded string.
- ///
- /// A shorthand for `to_hex_string(Case::Upper)`, so that `Case` doesn't need to be imported.
- ///
- /// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
- #[cfg(feature = "alloc")]
- fn to_upper_hex_string(self) -> String { self.to_hex_string(Case::Upper) }
-
- /// Create a hex-encoded string.
- ///
- /// This may be faster than `.display_hex().to_string()` because it uses `reserve_suggestion`.
- #[cfg(feature = "alloc")]
- fn to_hex_string(self, case: Case) -> String {
- let mut string = String::new();
- self.append_hex_to_string(case, &mut string);
- string
- }
-
- /// Appends hex-encoded content to an existing `String`.
- ///
- /// This may be faster than `write!(string, "{:x}", self.as_hex())` because it uses
- /// `hex_reserve_sugggestion`.
- #[cfg(feature = "alloc")]
- fn append_hex_to_string(self, case: Case, string: &mut String) {
- use fmt::Write;
-
- string.reserve(self.hex_reserve_suggestion());
- match case {
- Case::Lower => write!(string, "{:x}", self.as_hex()),
- Case::Upper => write!(string, "{:X}", self.as_hex()),
- }
- .unwrap_or_else(|_| {
- let name = core::any::type_name::<Self::Display>();
- // We don't expect `std` to ever be buggy, so the bug is most likely in the `Display`
- // impl of `Self::Display`.
- panic!("The implementation of Display for {} returned an error when it shouldn't", name)
- })
- }
-
- /// Hints how much bytes to reserve when creating a `String`.
- ///
- /// Implementors that know the number of produced bytes upfront should override this.
- /// Defaults to 0.
- ///
- // We prefix the name with `hex_` to avoid potential collision with other methods.
- fn hex_reserve_suggestion(self) -> usize { 0 }
-}
-
-mod sealed {
- /// Trait marking a shared reference.
- pub trait IsRef: Copy {}
-
- impl<T: ?Sized> IsRef for &'_ T {}
-}
-
-impl<'a> DisplayHex for &'a [u8] {
- type Display = DisplayByteSlice<'a>;
-
- #[inline]
- fn as_hex(self) -> Self::Display { DisplayByteSlice { bytes: self } }
-
- #[inline]
- fn hex_reserve_suggestion(self) -> usize {
- // Since the string wouldn't fit into address space if this overflows (actually even for
- // smaller amounts) it's better to panic right away. It should also give the optimizer
- // better opportunities.
- self.len().checked_mul(2).expect("the string wouldn't fit into address space")
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<'a> DisplayHex for &'a alloc::vec::Vec<u8> {
- type Display = DisplayByteSlice<'a>;
-
- #[inline]
- fn as_hex(self) -> Self::Display { DisplayByteSlice { bytes: self } }
-
- #[inline]
- fn hex_reserve_suggestion(self) -> usize {
- // Since the string wouldn't fit into address space if this overflows (actually even for
- // smaller amounts) it's better to panic right away. It should also give the optimizer
- // better opportunities.
- self.len().checked_mul(2).expect("the string wouldn't fit into address space")
- }
-}
-
-/// Displays byte slice as hex.
-///
-/// Created by [`<&[u8] as DisplayHex>::as_hex`](DisplayHex::as_hex).
-pub struct DisplayByteSlice<'a> {
- // pub because we want to keep lengths in sync
- pub(crate) bytes: &'a [u8],
-}
-
-impl<'a> DisplayByteSlice<'a> {
- fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
- use fmt::Write;
- // There are at least two optimizations left:
- //
- // * Reusing the buffer (encoder) which may decrease the number of virtual calls
- // * Not recursing, avoiding another 1024B allocation and zeroing
- //
- // This would complicate the code so I was too lazy to do them but feel free to send a PR!
-
- let mut encoder = BufEncoder::<1024>::new();
-
- let pad_right = if let Some(width) = f.width() {
- let string_len = match f.precision() {
- Some(max) if self.bytes.len() * 2 > (max + 1) / 2 => max,
- Some(_) | None => self.bytes.len() * 2,
- };
-
- if string_len < width {
- let (left, right) = match f.align().unwrap_or(fmt::Alignment::Left) {
- fmt::Alignment::Left => (0, width - string_len),
- fmt::Alignment::Right => (width - string_len, 0),
- fmt::Alignment::Center =>
- ((width - string_len) / 2, (width - string_len + 1) / 2),
- };
- // Avoid division by zero and optimize for common case.
- if left > 0 {
- let c = f.fill();
- let chunk_len = encoder.put_filler(c, left);
- let padding = encoder.as_str();
- for _ in 0..(left / chunk_len) {
- f.write_str(padding)?;
- }
- f.write_str(&padding[..((left % chunk_len) * c.len_utf8())])?;
- encoder.clear();
- }
- right
- } else {
- 0
- }
- } else {
- 0
- };
-
- match f.precision() {
- Some(max) if self.bytes.len() > (max + 1) / 2 => {
- write!(f, "{}", self.bytes[..(max / 2)].as_hex())?;
- if max % 2 == 1 && self.bytes.len() > max / 2 + 1 {
- f.write_char(
- case.table().byte_to_hex(self.bytes[max / 2 + 1]).as_bytes()[1].into(),
- )?;
- }
- }
- Some(_) | None => {
- let mut chunks = self.bytes.chunks_exact(512);
- for chunk in &mut chunks {
- encoder.put_bytes(chunk, case);
- f.write_str(encoder.as_str())?;
- encoder.clear();
- }
- encoder.put_bytes(chunks.remainder(), case);
- f.write_str(encoder.as_str())?;
- }
- }
-
- // Avoid division by zero and optimize for common case.
- if pad_right > 0 {
- encoder.clear();
- let c = f.fill();
- let chunk_len = encoder.put_filler(c, pad_right);
- let padding = encoder.as_str();
- for _ in 0..(pad_right / chunk_len) {
- f.write_str(padding)?;
- }
- f.write_str(&padding[..((pad_right % chunk_len) * c.len_utf8())])?;
- }
- Ok(())
- }
-}
-
-impl<'a> fmt::Display for DisplayByteSlice<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
-}
-
-impl<'a> fmt::Debug for DisplayByteSlice<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
-}
-
-impl<'a> fmt::LowerHex for DisplayByteSlice<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
-}
-
-impl<'a> fmt::UpperHex for DisplayByteSlice<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
-}
-
-/// Displays byte array as hex.
-///
-/// Created by [`<&[u8; CAP / 2] as DisplayHex>::as_hex`](DisplayHex::as_hex).
-pub struct DisplayArray<'a, const CAP: usize> {
- array: &'a [u8],
-}
-
-impl<'a, const CAP: usize> DisplayArray<'a, CAP> {
- /// Creates the wrapper.
- ///
- /// # Panics
- ///
- /// When the length of array is greater than capacity / 2.
- #[inline]
- fn new(array: &'a [u8]) -> Self {
- assert!(array.len() <= CAP / 2);
- DisplayArray { array }
- }
-
- fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
- let mut encoder = BufEncoder::<CAP>::new();
- encoder.put_bytes(self.array, case);
- f.pad_integral(true, "0x", encoder.as_str())
- }
-}
-
-impl<'a, const LEN: usize> fmt::Display for DisplayArray<'a, LEN> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
-}
-
-impl<'a, const LEN: usize> fmt::Debug for DisplayArray<'a, LEN> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
-}
-
-impl<'a, const LEN: usize> fmt::LowerHex for DisplayArray<'a, LEN> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
-}
-
-impl<'a, const LEN: usize> fmt::UpperHex for DisplayArray<'a, LEN> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
-}
-
-macro_rules! impl_array_as_hex {
- ($($len:expr),*) => {
- $(
- impl<'a> DisplayHex for &'a [u8; $len] {
- type Display = DisplayArray<'a, {$len * 2}>;
-
- fn as_hex(self) -> Self::Display {
- DisplayArray::new(self)
- }
- }
- )*
- }
-}
-
-impl_array_as_hex!(
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 32, 33, 64, 65, 128, 256, 512, 1024,
- 2048, 4096
-);
-
-/// Format known-length array as hex.
-///
-/// This supports all formatting options of formatter and may be faster than calling `as_hex()` on
-/// an arbitrary `&[u8]`. Note that the implementation intentionally keeps leading zeros even when
-/// not requested. This is designed to display values such as hashes and keys and removing leading
-/// zeros would be confusing.
-///
-/// Note that the bytes parameter is `IntoIterator` this means that if you would like to do some
-/// manipulation to the byte array before formatting then you can. For example `bytes.iter().rev()`
-/// to print the array backwards.
-///
-/// ## Parameters
-///
-/// * `$formatter` - a [`fmt::Formatter`].
-/// * `$len` known length of `$bytes`, must be a const expression.
-/// * `$bytes` - bytes to be encoded, most likely a reference to an array.
-/// * `$case` - value of type [`Case`] determining whether to format as lower or upper case.
-///
-/// ## Panics
-///
-/// This macro panics if `$len` is not equal to `$bytes.len()`. It also fails to compile if `$len`
-/// is more than half of `usize::MAX`.
-#[macro_export]
-macro_rules! fmt_hex_exact {
- ($formatter:expr, $len:expr, $bytes:expr, $case:expr) => {{
- // statically check $len
- #[allow(deprecated)]
- const _: () = [()][($len > usize::MAX / 2) as usize];
- assert_eq!($bytes.len(), $len);
- $crate::display::fmt_hex_exact_fn::<_, { $len * 2 }>($formatter, $bytes, $case)
- }};
-}
-pub use fmt_hex_exact;
-
-/// Adds `core::fmt` trait implementations to type `$ty`.
-///
-/// Implements:
-///
-/// - `fmt::{LowerHex, UpperHex}` using [`fmt_hex_exact`].
-/// - `fmt::{Display, Debug}` by calling `LowerHex`.
-///
-/// Requires:
-///
-/// - `$ty` must implement `IntoIterator<Item=Borrow<u8>>`.
-///
-/// ## Parameters
-///
-/// * `$ty` - the type to implement traits on.
-/// * `$len` - known length of `$bytes`, must be a const expression.
-/// * `$bytes` - bytes to be encoded, most likely a reference to an array.
-/// * `$reverse` - true if you want the array to be displayed backwards.
-/// * `$gen: $gent` - optional generic type(s) and trait bound(s) to put on `$ty` e.g, `F: Foo`.
-///
-/// ## Examples
-///
-/// ```
-/// # use core::borrow::Borrow;
-/// # use hex_conservative::impl_fmt_traits;
-/// struct Wrapper([u8; 4]);
-///
-/// impl Borrow<[u8]> for Wrapper {
-/// fn borrow(&self) -> &[u8] { &self.0[..] }
-/// }
-///
-/// impl_fmt_traits! {
-/// impl fmt_traits for Wrapper {
-/// const LENGTH: usize = 4;
-/// }
-/// }
-///
-/// let w = Wrapper([0x12, 0x34, 0x56, 0x78]);
-/// assert_eq!(format!("{}", w), "12345678");
-/// ```
-///
-/// We support generics on `$ty`:
-///
-/// ```
-/// # use core::borrow::Borrow;
-/// # use core::marker::PhantomData;
-/// # use hex_conservative::impl_fmt_traits;
-/// struct Wrapper<T>([u8; 4], PhantomData<T>);
-///
-/// // `Clone` is just some arbitrary trait.
-/// impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
-/// fn borrow(&self) -> &[u8] { &self.0[..] }
-/// }
-///
-/// impl_fmt_traits! {
-/// impl<T: Clone> fmt_traits for Wrapper<T> {
-/// const LENGTH: usize = 4;
-/// }
-/// }
-///
-/// let w = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
-/// assert_eq!(format!("{}", w), "12345678");
-/// ```
-///
-/// And also, as is required by `rust-bitcoin`, we support displaying
-/// the hex string byte-wise backwards:
-///
-/// ```
-/// # use core::borrow::Borrow;
-/// # use hex_conservative::impl_fmt_traits;
-/// struct Wrapper([u8; 4]);
-///
-/// impl Borrow<[u8]> for Wrapper {
-/// fn borrow(&self) -> &[u8] { &self.0[..] }
-/// }
-///
-/// impl_fmt_traits! {
-/// #[display_backward(true)]
-/// impl fmt_traits for Wrapper {
-/// const LENGTH: usize = 4;
-/// }
-/// }
-/// let w = Wrapper([0x12, 0x34, 0x56, 0x78]);
-/// assert_eq!(format!("{}", w), "78563412");
-/// ```
-#[macro_export]
-macro_rules! impl_fmt_traits {
- // Without generic and trait bounds and without display_backward attribute.
- (impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
- $crate::impl_fmt_traits! {
- #[display_backward(false)]
- impl<> fmt_traits for $ty<> {
- const LENGTH: usize = $len;
- }
- }
- };
- // Without generic and trait bounds and with display_backward attribute.
- (#[display_backward($reverse:expr)] impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
- $crate::impl_fmt_traits! {
- #[display_backward($reverse)]
- impl<> fmt_traits for $ty<> {
- const LENGTH: usize = $len;
- }
- }
- };
- // With generic and trait bounds and without display_backward attribute.
- (impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
- $crate::impl_fmt_traits! {
- #[display_backward(false)]
- impl<$($gen: $gent),*> fmt_traits for $ty<$($unused),*> {
- const LENGTH: usize = $len;
- }
- }
- };
- // With generic and trait bounds and display_backward attribute.
- (#[display_backward($reverse:expr)] impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
- impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
- #[inline]
- fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
- let case = $crate::Case::Lower;
-
- if $reverse {
- let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
- $crate::fmt_hex_exact!(f, $len, bytes, case)
- } else {
- let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
- $crate::fmt_hex_exact!(f, $len, bytes, case)
- }
- }
- }
-
- impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
- #[inline]
- fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
- let case = $crate::Case::Upper;
-
- if $reverse {
- let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
- $crate::fmt_hex_exact!(f, $len, bytes, case)
- } else {
- let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
- $crate::fmt_hex_exact!(f, $len, bytes, case)
- }
- }
- }
-
- impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
- #[inline]
- fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
- $crate::_export::_core::fmt::LowerHex::fmt(self, f)
- }
- }
-
- impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
- #[inline]
- fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
- $crate::_export::_core::fmt::LowerHex::fmt(&self, f)
- }
- }
- };
-}
-pub use impl_fmt_traits;
-
-// Implementation detail of `write_hex_exact` macro to de-duplicate the code
-//
-// Whether hex is an integer or a string is debatable, we cater a little bit to each.
-// - We support users adding `0x` prefix using "{:#}" (treating hex like an integer).
-// - We support limiting the output using precision "{:.10}" (treating hex like a string).
-#[doc(hidden)]
-#[inline]
-pub fn fmt_hex_exact_fn<I, const N: usize>(
- f: &mut fmt::Formatter,
- bytes: I,
- case: Case,
-) -> fmt::Result
-where
- I: IntoIterator,
- I::Item: Borrow<u8>,
-{
- let mut encoder = BufEncoder::<N>::new();
- encoder.put_bytes(bytes, case);
- let encoded = encoder.as_str();
-
- if let Some(precision) = f.precision() {
- if encoded.len() > precision {
- return f.pad_integral(true, "0x", &encoded[..precision]);
- }
- }
- f.pad_integral(true, "0x", encoded)
-}
-
-#[cfg(test)]
-mod tests {
- #[cfg(feature = "alloc")]
- use super::*;
-
- #[cfg(feature = "alloc")]
- mod alloc {
- use core::marker::PhantomData;
-
- use super::*;
-
- fn check_encoding(bytes: &[u8]) {
- use core::fmt::Write;
-
- let s1 = bytes.to_lower_hex_string();
- let mut s2 = String::with_capacity(bytes.len() * 2);
- for b in bytes {
- write!(s2, "{:02x}", b).unwrap();
- }
- assert_eq!(s1, s2);
- }
-
- #[test]
- fn empty() { check_encoding(b""); }
-
- #[test]
- fn single() { check_encoding(b"*"); }
-
- #[test]
- fn two() { check_encoding(b"*x"); }
-
- #[test]
- fn just_below_boundary() { check_encoding(&[42; 512]); }
-
- #[test]
- fn just_above_boundary() { check_encoding(&[42; 513]); }
-
- #[test]
- fn just_above_double_boundary() { check_encoding(&[42; 1025]); }
-
- #[test]
- fn fmt_exact_macro() {
- use crate::alloc::string::ToString;
-
- struct Dummy([u8; 32]);
-
- impl fmt::Display for Dummy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt_hex_exact!(f, 32, &self.0, Case::Lower)
- }
- }
- let dummy = Dummy([42; 32]);
- assert_eq!(dummy.to_string(), "2a".repeat(32));
- assert_eq!(format!("{:.10}", dummy), "2a".repeat(5));
- }
-
- #[test]
- fn display_short_with_padding() {
- let v = vec![0xbe, 0xef];
- assert_eq!(format!("Hello {:<8}!", v.as_hex()), "Hello beef !");
- assert_eq!(format!("Hello {:-<8}!", v.as_hex()), "Hello beef----!");
- assert_eq!(format!("Hello {:^8}!", v.as_hex()), "Hello beef !");
- assert_eq!(format!("Hello {:>8}!", v.as_hex()), "Hello beef!");
- }
-
- #[test]
- fn display_long() {
- // Note this string is shorter than the one above.
- let v = vec![0xab; 512];
- let mut want = "0".repeat(2000 - 1024);
- want.extend(core::iter::repeat("ab").take(512));
- let got = format!("{:0>2000}", v.as_hex());
- assert_eq!(got, want)
- }
-
- // Precision and padding act the same as for strings in the stdlib (because we use `Formatter::pad`).
-
- #[test]
- fn precision_truncates() {
- // Precision gets the most significant bytes.
- let v = vec![0x12, 0x34, 0x56, 0x78];
- // Remember the integer is number of hex chars not number of bytes.
- assert_eq!(format!("{0:.4}", v.as_hex()), "1234");
- }
-
- #[test]
- fn precision_with_padding_truncates() {
- // Precision gets the most significant bytes.
- let v = vec![0x12, 0x34, 0x56, 0x78];
- assert_eq!(format!("{0:10.4}", v.as_hex()), "1234 ");
- }
-
- #[test]
- fn precision_with_padding_pads_right() {
- let v = vec![0x12, 0x34, 0x56, 0x78];
- assert_eq!(format!("{0:10.20}", v.as_hex()), "12345678 ");
- }
-
- #[test]
- fn precision_with_padding_pads_left() {
- let v = vec![0x12, 0x34, 0x56, 0x78];
- assert_eq!(format!("{0:>10.20}", v.as_hex()), " 12345678");
- }
-
- #[test]
- fn precision_with_padding_pads_center() {
- let v = vec![0x12, 0x34, 0x56, 0x78];
- assert_eq!(format!("{0:^10.20}", v.as_hex()), " 12345678 ");
- }
-
- #[test]
- fn precision_with_padding_pads_center_odd() {
- let v = vec![0x12, 0x34, 0x56, 0x78];
- assert_eq!(format!("{0:^11.20}", v.as_hex()), " 12345678 ");
- }
-
- #[test]
- fn precision_does_not_extend() {
- let v = vec![0x12, 0x34, 0x56, 0x78];
- assert_eq!(format!("{0:.16}", v.as_hex()), "12345678");
- }
-
- #[test]
- fn padding_extends() {
- let v = vec![0xab; 2];
- assert_eq!(format!("{:0>8}", v.as_hex()), "0000abab");
- }
-
- #[test]
- fn padding_does_not_truncate() {
- let v = vec![0x12, 0x34, 0x56, 0x78];
- assert_eq!(format!("{:0>4}", v.as_hex()), "12345678");
- }
-
- #[test]
- fn hex_fmt_impl_macro_forward() {
- struct Wrapper([u8; 4]);
-
- impl Borrow<[u8]> for Wrapper {
- fn borrow(&self) -> &[u8] { &self.0[..] }
- }
-
- impl_fmt_traits! {
- #[display_backward(false)]
- impl fmt_traits for Wrapper {
- const LENGTH: usize = 4;
- }
- }
-
- let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
-
- let want = "12345678";
- let got = format!("{}", tc);
- assert_eq!(got, want);
- }
-
- #[test]
- fn hex_fmt_impl_macro_backwards() {
- struct Wrapper([u8; 4]);
-
- impl Borrow<[u8]> for Wrapper {
- fn borrow(&self) -> &[u8] { &self.0[..] }
- }
-
- impl_fmt_traits! {
- #[display_backward(true)]
- impl fmt_traits for Wrapper {
- const LENGTH: usize = 4;
- }
- }
-
- let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
-
- let want = "78563412";
- let got = format!("{}", tc);
- assert_eq!(got, want);
- }
-
- #[test]
- fn hex_fmt_impl_macro_gen_forward() {
- struct Wrapper<T>([u8; 4], PhantomData<T>);
-
- impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
- fn borrow(&self) -> &[u8] { &self.0[..] }
- }
-
- impl_fmt_traits! {
- #[display_backward(false)]
- impl<T: Clone> fmt_traits for Wrapper<T> {
- const LENGTH: usize = 4;
- }
- }
-
- // We just use `u32` here as some arbitrary type that implements some arbitrary trait.
- let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
-
- let want = "12345678";
- let got = format!("{}", tc);
- assert_eq!(got, want);
- }
-
- #[test]
- fn hex_fmt_impl_macro_gen_backwards() {
- struct Wrapper<T>([u8; 4], PhantomData<T>);
-
- impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
- fn borrow(&self) -> &[u8] { &self.0[..] }
- }
-
- impl_fmt_traits! {
- #[display_backward(true)]
- impl<T: Clone> fmt_traits for Wrapper<T> {
- const LENGTH: usize = 4;
- }
- }
-
- // We just use `u32` here as some arbitrary type that implements some arbitrary trait.
- let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
-
- let want = "78563412";
- let got = format!("{}", tc);
- assert_eq!(got, want);
- }
- }
-}
diff --git a/external/vendor/hex-conservative/src/error.rs b/external/vendor/hex-conservative/src/error.rs
index 8b85a2e..d526ac9 100644
--- a/external/vendor/hex-conservative/src/error.rs
+++ b/external/vendor/hex-conservative/src/error.rs
@@ -1,72 +1,152 @@
// SPDX-License-Identifier: CC0-1.0
-//! Error code for the `hex-conservative` crate.
+//! The error types.
+//!
+//! These types are returned when hex decoding fails. The high-level ones are
+//! [`DecodeFixedLengthBytesError`] and [`DecodeVariableLengthBytesError`] which represent all
+//! possible ways in which hex decoding may fail in the two most common decoding scenarios.
+use core::convert::Infallible;
use core::fmt;
+#[cfg(feature = "std")]
+use std::error::Error as StdError;
+#[cfg(all(not(feature = "std"), feature = "newer-rust-version"))]
+if_rust_version::if_rust_version! {
+ >= 1.81 {
+ use core::error::Error as StdError;
+ }
+}
+
+#[cfg(feature = "std")]
+macro_rules! if_std_error {
+ ({ $($if_yes:tt)* } $(else { $($if_not:tt)* })?) => {
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "std", all(feature = "newer-rust-version", rust_version = ">= 1.81.0")))))]
+ $($if_yes)*
+ }
+}
+
+#[cfg(all(not(feature = "std"), feature = "newer-rust-version"))]
+macro_rules! if_std_error {
+ ({ $($if_yes:tt)* } $(else { $($if_not:tt)* })?) => {
+ if_rust_version::if_rust_version! {
+ >= 1.81 {
+ #[cfg_attr(docsrs, doc(cfg(any(feature = "std", all(feature = "newer-rust-version", rust_version = ">= 1.81.0")))))]
+ $($if_yes)*
+ } $(else { $($if_not)* })?
+ }
+ }
+}
-use crate::write_err;
+#[cfg(all(not(feature = "std"), not(feature = "newer-rust-version")))]
+macro_rules! if_std_error {
+ ({ $($if_yes:tt)* } $(else { $($if_not:tt)* })?) => {
+ $($($if_not)*)?
+ }
+}
/// Formats error.
///
/// If `std` feature is OFF appends error source (delimited by `: `). We do this because
/// `e.source()` is only available in std builds, without this macro the error source is lost for
/// no-std builds.
-#[macro_export]
macro_rules! write_err {
($writer:expr, $string:literal $(, $args:expr)*; $source:expr) => {
{
- #[cfg(feature = "std")]
- {
- let _ = &$source; // Prevents clippy warnings.
- write!($writer, $string $(, $args)*)
- }
- #[cfg(not(feature = "std"))]
- {
- write!($writer, concat!($string, ": {}") $(, $args)*, $source)
+ if_std_error! {
+ {
+ {
+ let _ = &$source; // Prevents clippy warnings.
+ write!($writer, $string $(, $args)*)
+ }
+ } else {
+ {
+ write!($writer, concat!($string, ": {}") $(, $args)*, $source)
+ }
+ }
}
}
}
}
+pub(crate) use write_err;
-/// Hex decoding error.
+/// Error returned when hex decoding a hex string with variable length.
+///
+/// This represents the first error encountered during decoding, however we may add other remaining
+/// ones in the future.
+///
+/// This error differs from [`DecodeFixedLengthBytesError`] in that the number of bytes is only known
+/// at run time - e.g. when decoding `Vec<u8>`.
#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum HexToBytesError {
+pub enum DecodeVariableLengthBytesError {
/// Non-hexadecimal character.
InvalidChar(InvalidCharError),
- /// Purported hex string had odd length.
+ /// Purported hex string had odd (not even) length.
OddLengthString(OddLengthStringError),
}
-impl fmt::Display for HexToBytesError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use HexToBytesError::*;
+impl DecodeVariableLengthBytesError {
+ /// Adds `by_bytes` to all character positions stored inside.
+ ///
+ /// If you're parsing a larger string that consists of multiple hex sub-strings and want to
+ /// return `InvalidCharError` you may need to use this function so that the callers of your
+ /// parsing function can tell the exact position where decoding failed relative to the start of
+ /// the string passed into your parsing function.
+ ///
+ /// Note that this function has the standard Rust overflow behavior because you should only
+ /// ever pass in the position of the parsed hex string relative to the start of the entire
+ /// input. In that case overflow is impossible.
+ ///
+ /// This method consumes and returns `self` so that calling it inside a closure passed into
+ /// [`Result::map_err`] is convenient.
+ #[must_use]
+ #[inline]
+ pub fn offset(self, by_bytes: usize) -> Self {
+ use DecodeVariableLengthBytesError as E;
- match *self {
- InvalidChar(ref e) => write_err!(f, "invalid char, failed to create bytes from hex"; e),
- OddLengthString(ref e) =>
- write_err!(f, "odd length, failed to create bytes from hex"; e),
+ match self {
+ E::InvalidChar(e) => E::InvalidChar(e.offset(by_bytes)),
+ E::OddLengthString(e) => E::OddLengthString(e),
}
}
}
-#[cfg(feature = "std")]
-impl std::error::Error for HexToBytesError {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- use HexToBytesError::*;
+impl From<Infallible> for DecodeVariableLengthBytesError {
+ #[inline]
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for DecodeVariableLengthBytesError {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use DecodeVariableLengthBytesError as E;
match *self {
- InvalidChar(ref e) => Some(e),
- OddLengthString(ref e) => Some(e),
+ E::InvalidChar(ref e) => write_err!(f, "failed to decode hex"; e),
+ E::OddLengthString(ref e) => write_err!(f, "failed to decode hex"; e),
}
}
}
-impl From<InvalidCharError> for HexToBytesError {
+if_std_error! {{
+ impl StdError for DecodeVariableLengthBytesError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ use DecodeVariableLengthBytesError as E;
+
+ match *self {
+ E::InvalidChar(ref e) => Some(e),
+ E::OddLengthString(ref e) => Some(e),
+ }
+ }
+ }
+}}
+
+impl From<InvalidCharError> for DecodeVariableLengthBytesError {
#[inline]
fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
}
-impl From<OddLengthStringError> for HexToBytesError {
+impl From<OddLengthStringError> for DecodeVariableLengthBytesError {
#[inline]
fn from(e: OddLengthStringError) -> Self { Self::OddLengthString(e) }
}
@@ -75,23 +155,100 @@ impl From<OddLengthStringError> for HexToBytesError {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidCharError {
pub(crate) invalid: u8,
+ pub(crate) pos: usize,
+}
+
+impl From<Infallible> for InvalidCharError {
+ #[inline]
+ fn from(never: Infallible) -> Self { match never {} }
}
impl InvalidCharError {
/// Returns the invalid character byte.
- pub fn invalid_char(&self) -> u8 { self.invalid }
+ #[inline]
+ pub(crate) fn invalid_char(&self) -> u8 { self.invalid }
+ /// Returns the position of the invalid character byte.
+ #[inline]
+ pub fn pos(&self) -> usize { self.pos }
+
+ /// Adds `by_bytes` to all character positions stored inside.
+ ///
+ /// **Important**: if you have `DecodeVariableLengthBytesError` or `DecodeFixedLengthBytesError` you
+ /// should call the method *on them* - do not match them and manually call this method. Doing
+ /// so may lead to broken behavior in the future.
+ ///
+ /// If you're parsing a larger string that consists of multiple hex sub-strings and want to
+ /// return `InvalidCharError` you may need to use this function so that the callers of your
+ /// parsing function can tell the exact position where decoding failed relative to the start of
+ /// the string passed into your parsing function.
+ ///
+ /// Note that this function has the standard Rust overflow behavior because you should only
+ /// ever pass in the position of the parsed hex string relative to the start of the entire
+ /// input. In that case overflow is impossible.
+ ///
+ /// This method consumes and returns `self` so that calling it inside a closure passed into
+ /// [`Result::map_err`] is convenient.
+ #[must_use]
+ #[inline]
+ pub fn offset(mut self, by_bytes: usize) -> Self {
+ self.pos += by_bytes;
+ self
+ }
}
+/// Note that the implementation displays position as 1-based instead of 0-based to be more
+/// suitable to end users who might be non-programmers.
impl fmt::Display for InvalidCharError {
+ #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "invalid hex char {}", self.invalid)
+ // We're displaying this for general audience, not programmers, so we want to do 1-based
+ // position but that might confuse programmers who might think it's 0-based. Hopefully
+ // using more wordy approach will avoid the confusion.
+
+ // format_args! would be simpler but we can't use it because of Rust issue #92698.
+ struct Format<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(F);
+ impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Display for Format<F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0(f) }
+ }
+
+ // The lifetime is not extended in MSRV, so we need this.
+ let which;
+ let which: &dyn fmt::Display = match self.pos() {
+ 0 => &"1st",
+ 1 => &"2nd",
+ 2 => &"3rd",
+ pos => {
+ which = Format(move |f| write!(f, "{}th", pos + 1));
+ &which
+ }
+ };
+
+ // The lifetime is not extended in MSRV, so we need these.
+ let chr_ascii;
+ let chr_non_ascii;
+
+ let invalid_char = self.invalid_char();
+ // We're currently not storing the entire character, so we need to make sure values >=
+ // 128 don't get misinterpreted as ISO-8859-1.
+ let chr: &dyn fmt::Display = if self.invalid_char().is_ascii() {
+ // Yes, the Debug output is correct here. Display would print the characters
+ // directly which would be confusing in case of control characters and it would
+ // also mess up the formatting. The `Debug` implementation of `char` properly
+ // escapes such characters.
+ chr_ascii = Format(move |f| write!(f, "{:?}", invalid_char as char));
+ &chr_ascii
+ } else {
+ chr_non_ascii = Format(move |f| write!(f, "{:#02x}", invalid_char));
+ &chr_non_ascii
+ };
+
+ write!(f, "the {} character, {}, is not a valid hex digit", which, chr)
}
}
-#[cfg(feature = "std")]
-impl std::error::Error for InvalidCharError {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
-}
+if_std_error! {{
+ impl StdError for InvalidCharError {}
+}}
/// Purported hex string had odd length.
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -99,81 +256,226 @@ pub struct OddLengthStringError {
pub(crate) len: usize,
}
+impl From<Infallible> for OddLengthStringError {
+ #[inline]
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
impl OddLengthStringError {
/// Returns the odd length of the input string.
+ #[inline]
pub fn length(&self) -> usize { self.len }
}
impl fmt::Display for OddLengthStringError {
+ #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "odd hex string length {}", self.len)
+ if self.length() == 1 {
+ write!(f, "the hex string is 1 byte long which is not an even number")
+ } else {
+ write!(f, "the hex string is {} bytes long which is not an even number", self.length())
+ }
}
}
-#[cfg(feature = "std")]
-impl std::error::Error for OddLengthStringError {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
-}
+if_std_error! {{
+ impl StdError for OddLengthStringError {}
+}}
-/// Hex decoding error.
+/// Error returned when hex decoding bytes whose length is known at compile time.
+///
+/// This error differs from [`DecodeVariableLengthBytesError`] in that the number of bytes is known at
+/// compile time - e.g. when decoding to an array of bytes.
#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum HexToArrayError {
+pub enum DecodeFixedLengthBytesError {
/// Non-hexadecimal character.
InvalidChar(InvalidCharError),
/// Tried to parse fixed-length hash from a string with the wrong length.
InvalidLength(InvalidLengthError),
}
-impl fmt::Display for HexToArrayError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use HexToArrayError::*;
+impl DecodeFixedLengthBytesError {
+ /// Adds `by_bytes` to all character positions stored inside.
+ ///
+ /// If you're parsing a larger string that consists of multiple hex sub-strings and want to
+ /// return `InvalidCharError` you may need to use this function so that the callers of your
+ /// parsing function can tell the exact position where decoding failed relative to the start of
+ /// the string passed into your parsing function.
+ ///
+ /// Note that this function has the standard Rust overflow behavior because you should only
+ /// ever pass in the position of the parsed hex string relative to the start of the entire
+ /// input. In that case overflow is impossible.
+ ///
+ /// This method consumes and returns `self` so that calling it inside a closure passed into
+ /// [`Result::map_err`] is convenient.
+ #[must_use]
+ #[inline]
+ pub fn offset(self, by_bytes: usize) -> Self {
+ use DecodeFixedLengthBytesError as E;
- match *self {
- InvalidChar(ref e) => crate::write_err!(f, "failed to parse hex digit"; e),
- InvalidLength(ref e) => write_err!(f, "failed to parse hex"; e),
+ match self {
+ E::InvalidChar(e) => E::InvalidChar(e.offset(by_bytes)),
+ E::InvalidLength(e) => E::InvalidLength(e),
}
}
}
-#[cfg(feature = "std")]
-impl std::error::Error for HexToArrayError {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- use HexToArrayError::*;
+impl From<Infallible> for DecodeFixedLengthBytesError {
+ #[inline]
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl fmt::Display for DecodeFixedLengthBytesError {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use DecodeFixedLengthBytesError as E;
match *self {
- InvalidChar(ref e) => Some(e),
- InvalidLength(ref e) => Some(e),
+ E::InvalidChar(ref e) => write_err!(f, "failed to parse hex"; e),
+ E::InvalidLength(ref e) => write_err!(f, "failed to parse hex"; e),
}
}
}
-impl From<InvalidCharError> for HexToArrayError {
+if_std_error! {{
+ impl StdError for DecodeFixedLengthBytesError {
+ #[inline]
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ use DecodeFixedLengthBytesError as E;
+
+ match *self {
+ E::InvalidChar(ref e) => Some(e),
+ E::InvalidLength(ref e) => Some(e),
+ }
+ }
+ }
+}}
+
+impl From<InvalidCharError> for DecodeFixedLengthBytesError {
#[inline]
fn from(e: InvalidCharError) -> Self { Self::InvalidChar(e) }
}
-impl From<InvalidLengthError> for HexToArrayError {
+impl From<InvalidLengthError> for DecodeFixedLengthBytesError {
#[inline]
fn from(e: InvalidLengthError) -> Self { Self::InvalidLength(e) }
}
/// Tried to parse fixed-length hash from a string with the wrong length.
#[derive(Debug, Clone, PartialEq, Eq)]
-#[non_exhaustive]
pub struct InvalidLengthError {
/// The expected length.
- pub expected: usize,
+ pub(crate) expected: usize,
/// The invalid length.
- pub invalid: usize,
+ pub(crate) invalid: usize,
+}
+
+impl From<Infallible> for InvalidLengthError {
+ #[inline]
+ fn from(never: Infallible) -> Self { match never {} }
+}
+
+impl InvalidLengthError {
+ /// Returns the expected length.
+ ///
+ /// Note that this represents both the number of bytes and the number of characters that needs
+ /// to be passed into the decoder, since the hex digits are ASCII and thus always 1-byte long.
+ #[inline]
+ pub fn expected_length(&self) -> usize { self.expected }
+
+ /// Returns the number of *hex bytes* passed to the hex decoder.
+ ///
+ /// Note that this does not imply the number of characters nor hex digits since they may be
+ /// invalid (wide unicode chars).
+ #[inline]
+ pub fn invalid_length(&self) -> usize { self.invalid }
}
impl fmt::Display for InvalidLengthError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "invilad hex string length {} (expected {})", self.invalid, self.expected)
+ write!(
+ f,
+ // Note on singular vs plural: expected length is never odd, so it cannot be 1
+ "the hex string is {} bytes long but exactly {} bytes were required",
+ self.invalid_length(),
+ self.expected_length()
+ )
}
}
+if_std_error! {{
+ impl StdError for InvalidLengthError {}
+}}
+
+#[cfg(test)]
#[cfg(feature = "std")]
-impl std::error::Error for InvalidLengthError {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
+mod tests {
+ use super::*;
+ use crate::{decode_to_array, decode_to_vec};
+
+ fn check_source<T: std::error::Error>(error: &T) {
+ assert!(error.source().is_some());
+ }
+
+ #[cfg(feature = "alloc")]
+ #[test]
+ fn invalid_char_error() {
+ let result = decode_to_vec("12G4");
+ let error = result.unwrap_err();
+ if let DecodeVariableLengthBytesError::InvalidChar(e) = error {
+ assert!(!format!("{}", e).is_empty());
+ assert_eq!(e.invalid_char(), b'G');
+ assert_eq!(e.pos(), 2);
+ } else {
+ panic!("Expected InvalidCharError");
+ }
+ }
+
+ #[cfg(feature = "alloc")]
+ #[test]
+ fn odd_length_string_error() {
+ let result = decode_to_vec("123");
+ let error = result.unwrap_err();
+ assert!(!format!("{}", error).is_empty());
+ check_source(&error);
+ if let DecodeVariableLengthBytesError::OddLengthString(e) = error {
+ assert!(!format!("{}", e).is_empty());
+ assert_eq!(e.length(), 3);
+ } else {
+ panic!("Expected OddLengthStringError");
+ }
+ }
+
+ #[test]
+ fn invalid_length_error() {
+ let result = decode_to_array::<4>("123");
+ let error = result.unwrap_err();
+ assert!(!format!("{}", error).is_empty());
+ check_source(&error);
+ if let DecodeFixedLengthBytesError::InvalidLength(e) = error {
+ assert!(!format!("{}", e).is_empty());
+ assert_eq!(e.expected_length(), 8);
+ assert_eq!(e.invalid_length(), 3);
+ } else {
+ panic!("Expected InvalidLengthError");
+ }
+ }
+
+ #[test]
+ fn to_bytes_error() {
+ let error =
+ DecodeVariableLengthBytesError::OddLengthString(OddLengthStringError { len: 7 });
+ assert!(!format!("{}", error).is_empty());
+ check_source(&error);
+ }
+
+ #[test]
+ fn to_array_error() {
+ let error = DecodeFixedLengthBytesError::InvalidLength(InvalidLengthError {
+ expected: 8,
+ invalid: 7,
+ });
+ assert!(!format!("{}", error).is_empty());
+ check_source(&error);
+ }
}
diff --git a/external/vendor/hex-conservative/src/iter.rs b/external/vendor/hex-conservative/src/iter.rs
index d1798b0..61332a1 100644
--- a/external/vendor/hex-conservative/src/iter.rs
+++ b/external/vendor/hex-conservative/src/iter.rs
@@ -8,17 +8,18 @@ use core::str;
#[cfg(feature = "std")]
use std::io;
-#[cfg(all(feature = "core2", not(feature = "std")))]
-use core2::io;
-
+#[cfg(feature = "alloc")]
+use crate::alloc::vec::Vec;
use crate::error::{InvalidCharError, OddLengthStringError};
-/// Convenience alias for `HexToBytesIter<HexDigitsIter<'a>>`.
-pub type HexSliceToBytesIter<'a> = HexToBytesIter<HexDigitsIter<'a>>;
-
/// Iterator yielding bytes decoded from an iterator of pairs of hex digits.
-pub struct HexToBytesIter<T: Iterator<Item = [u8; 2]>> {
- iter: T,
+#[derive(Debug)]
+pub struct HexToBytesIter<I>
+where
+ I: Iterator<Item = [u8; 2]>,
+{
+ iter: I,
+ original_len: usize,
}
impl<'a> HexToBytesIter<HexDigitsIter<'a>> {
@@ -28,7 +29,8 @@ impl<'a> HexToBytesIter<HexDigitsIter<'a>> {
///
/// If the input string is of odd length.
#[inline]
- pub fn new(s: &'a str) -> Result<Self, OddLengthStringError> {
+ #[allow(dead_code)] // Remove this when making HexToBytesIter public.
+ pub(crate) fn new(s: &'a str) -> Result<Self, OddLengthStringError> {
if s.len() % 2 != 0 {
Err(OddLengthStringError { len: s.len() })
} else {
@@ -36,59 +38,138 @@ impl<'a> HexToBytesIter<HexDigitsIter<'a>> {
}
}
+ #[inline]
pub(crate) fn new_unchecked(s: &'a str) -> Self {
Self::from_pairs(HexDigitsIter::new_unchecked(s.as_bytes()))
}
+
+ /// Writes all the bytes yielded by this `HexToBytesIter` to the provided slice.
+ ///
+ /// Stops writing if this `HexToBytesIter` yields an `InvalidCharError`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the length of this `HexToBytesIter` is not equal to the length of the provided
+ /// slice.
+ pub(crate) fn drain_to_slice(self, buf: &mut [u8]) -> Result<(), InvalidCharError> {
+ assert_eq!(self.len(), buf.len());
+ let mut ptr = buf.as_mut_ptr();
+ for byte in self {
+ // SAFETY: for loop iterates `len` times, and `buf` has length `len`
+ unsafe {
+ core::ptr::write(ptr, byte?);
+ ptr = ptr.add(1);
+ }
+ }
+ Ok(())
+ }
+
+ /// Writes all the bytes yielded by this `HexToBytesIter` to a `Vec<u8>`.
+ ///
+ /// This is equivalent to the combinator chain `iter().map().collect()` but was found by
+ /// benchmarking to be faster.
+ #[cfg(feature = "alloc")]
+ pub(crate) fn drain_to_vec(self) -> Result<Vec<u8>, InvalidCharError> {
+ let len = self.len();
+ let mut ret = Vec::with_capacity(len);
+ let mut ptr = ret.as_mut_ptr();
+ for byte in self {
+ // SAFETY: for loop iterates `len` times, and `ret` has a capacity of at least `len`
+ unsafe {
+ // docs: "`core::ptr::write` is appropriate for initializing uninitialized memory"
+ core::ptr::write(ptr, byte?);
+ ptr = ptr.add(1);
+ }
+ }
+ // SAFETY: `len` elements have been initialized, and `ret` has a capacity of at least `len`
+ unsafe {
+ ret.set_len(len);
+ }
+ Ok(ret)
+ }
}
-impl<T: Iterator<Item = [u8; 2]>> HexToBytesIter<T> {
+impl<I> HexToBytesIter<I>
+where
+ I: Iterator<Item = [u8; 2]> + ExactSizeIterator,
+{
/// Constructs a custom hex decoding iterator from another iterator.
#[inline]
- pub fn from_pairs(iter: T) -> Self { Self { iter } }
+ pub fn from_pairs(iter: I) -> Self { Self { original_len: iter.len(), iter } }
}
-impl<T: Iterator<Item = [u8; 2]>> Iterator for HexToBytesIter<T> {
+impl<I> Iterator for HexToBytesIter<I>
+where
+ I: Iterator<Item = [u8; 2]> + ExactSizeIterator,
+{
type Item = Result<u8, InvalidCharError>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let [hi, lo] = self.iter.next()?;
- Some(hex_chars_to_byte(hi, lo))
+ Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
+ invalid: c,
+ pos: if is_high {
+ (self.original_len - self.iter.len() - 1) * 2
+ } else {
+ (self.original_len - self.iter.len() - 1) * 2 + 1
+ },
+ }))
}
#[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (min, max) = self.iter.size_hint();
- (min / 2, max.map(|x| x / 2))
- }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
let [hi, lo] = self.iter.nth(n)?;
- Some(hex_chars_to_byte(hi, lo))
+ Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
+ invalid: c,
+ pos: if is_high {
+ (self.original_len - self.iter.len() - 1) * 2
+ } else {
+ (self.original_len - self.iter.len() - 1) * 2 + 1
+ },
+ }))
}
}
-impl<T: Iterator<Item = [u8; 2]> + DoubleEndedIterator> DoubleEndedIterator for HexToBytesIter<T> {
+impl<I> DoubleEndedIterator for HexToBytesIter<I>
+where
+ I: Iterator<Item = [u8; 2]> + DoubleEndedIterator + ExactSizeIterator,
+{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let [hi, lo] = self.iter.next_back()?;
- Some(hex_chars_to_byte(hi, lo))
+ Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
+ invalid: c,
+ pos: if is_high { self.iter.len() * 2 } else { self.iter.len() * 2 + 1 },
+ }))
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
let [hi, lo] = self.iter.nth_back(n)?;
- Some(hex_chars_to_byte(hi, lo))
+ Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
+ invalid: c,
+ pos: if is_high { self.iter.len() * 2 } else { self.iter.len() * 2 + 1 },
+ }))
}
}
-impl<T: Iterator<Item = [u8; 2]> + ExactSizeIterator> ExactSizeIterator for HexToBytesIter<T> {}
+impl<I> ExactSizeIterator for HexToBytesIter<I> where I: Iterator<Item = [u8; 2]> + ExactSizeIterator
+{}
-impl<T: Iterator<Item = [u8; 2]> + FusedIterator> FusedIterator for HexToBytesIter<T> {}
+impl<I> FusedIterator for HexToBytesIter<I> where
+ I: Iterator<Item = [u8; 2]> + ExactSizeIterator + FusedIterator
+{
+}
-#[cfg(any(feature = "std", feature = "core2"))]
-impl<T: Iterator<Item = [u8; 2]> + FusedIterator> io::Read for HexToBytesIter<T> {
+#[cfg(feature = "std")]
+impl<I> io::Read for HexToBytesIter<I>
+where
+ I: Iterator<Item = [u8; 2]> + ExactSizeIterator + FusedIterator,
+{
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut bytes_read = 0usize;
@@ -98,7 +179,8 @@ impl<T: Iterator<Item = [u8; 2]> + FusedIterator> io::Read for HexToBytesIter<T>
*dst = src;
bytes_read += 1;
}
- _ => break,
+ Some(Err(e)) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)),
+ None => break,
}
}
Ok(bytes_read)
@@ -110,6 +192,7 @@ impl<T: Iterator<Item = [u8; 2]> + FusedIterator> io::Read for HexToBytesIter<T>
/// Generally you shouldn't need to refer to this or bother with it and just use
/// [`HexToBytesIter::new`] consuming the returned value and use `HexSliceToBytesIter` if you need
/// to refer to the iterator in your types.
+#[derive(Debug)]
pub struct HexDigitsIter<'a> {
// Invariant: the length of the chunks is 2.
// Technically, this is `iter::Map` but we can't use it because fn is anonymous.
@@ -122,7 +205,7 @@ impl<'a> HexDigitsIter<'a> {
fn new_unchecked(digits: &'a [u8]) -> Self { Self { iter: digits.chunks_exact(2) } }
}
-impl<'a> Iterator for HexDigitsIter<'a> {
+impl Iterator for HexDigitsIter<'_> {
type Item = [u8; 2];
#[inline]
@@ -139,7 +222,7 @@ impl<'a> Iterator for HexDigitsIter<'a> {
}
}
-impl<'a> DoubleEndedIterator for HexDigitsIter<'a> {
+impl DoubleEndedIterator for HexDigitsIter<'_> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
@@ -151,176 +234,224 @@ impl<'a> DoubleEndedIterator for HexDigitsIter<'a> {
}
}
-impl<'a> ExactSizeIterator for HexDigitsIter<'a> {}
+impl ExactSizeIterator for HexDigitsIter<'_> {}
-impl<'a> core::iter::FusedIterator for HexDigitsIter<'a> {}
+impl core::iter::FusedIterator for HexDigitsIter<'_> {}
/// `hi` and `lo` are bytes representing hex characters.
-fn hex_chars_to_byte(hi: u8, lo: u8) -> Result<u8, InvalidCharError> {
- let hih = (hi as char).to_digit(16).ok_or(InvalidCharError { invalid: hi })?;
- let loh = (lo as char).to_digit(16).ok_or(InvalidCharError { invalid: lo })?;
+///
+/// Returns the valid byte or the invalid input byte and a bool indicating error for `hi` or `lo`.
+fn hex_chars_to_byte(hi: u8, lo: u8) -> Result<u8, (u8, bool)> {
+ let hih = (hi as char).to_digit(16).ok_or((hi, true))?;
+ let loh = (lo as char).to_digit(16).ok_or((lo, false))?;
let ret = (hih << 4) + loh;
Ok(ret as u8)
}
-/// Iterator over bytes which encodes the bytes and yields hex characters.
-pub struct BytesToHexIter<I: Iterator<Item = u8>> {
- /// The iterator whose next byte will be encoded to yield hex characters.
- iter: I,
- /// The low character of the pair (high, low) of hex characters encoded per byte.
- low: Option<char>,
-}
+#[cfg(test)]
+mod tests {
+ use super::*;
-impl<I> BytesToHexIter<I>
-where
- I: Iterator<Item = u8>,
-{
- /// Constructs a new `BytesToHexIter` from a byte iterator.
- pub fn new(iter: I) -> BytesToHexIter<I> { Self { iter, low: None } }
-}
+ #[test]
+ fn decode_iter_forward() {
+ let hex = "deadbeef";
+ let bytes = [0xde, 0xad, 0xbe, 0xef];
-impl<I> Iterator for BytesToHexIter<I>
-where
- I: Iterator<Item = u8>,
-{
- type Item = char;
+ for (i, b) in HexToBytesIter::new(hex).unwrap().enumerate() {
+ assert_eq!(b.unwrap(), bytes[i]);
+ }
- #[inline]
- fn next(&mut self) -> Option<char> {
- match self.low {
- Some(c) => {
- self.low = None;
- Some(c)
- }
- None => self.iter.next().map(|b| {
- let (high, low) = byte_to_hex_chars(b);
- self.low = Some(low);
- high
- }),
+ let mut iter = HexToBytesIter::new(hex).unwrap();
+ for i in (0..=bytes.len()).rev() {
+ assert_eq!(iter.len(), i);
+ let _ = iter.next();
}
}
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (min, max) = self.iter.size_hint();
- match self.low {
- Some(_) => (min * 2 + 1, max.map(|max| max * 2 + 1)),
- None => (min * 2, max.map(|max| max * 2)),
+ #[test]
+ fn decode_iter_backward() {
+ let hex = "deadbeef";
+ let bytes = [0xef, 0xbe, 0xad, 0xde];
+
+ for (i, b) in HexToBytesIter::new(hex).unwrap().rev().enumerate() {
+ assert_eq!(b.unwrap(), bytes[i]);
}
- }
-}
-impl<I> DoubleEndedIterator for BytesToHexIter<I>
-where
- I: DoubleEndedIterator + Iterator<Item = u8>,
-{
- #[inline]
- fn next_back(&mut self) -> Option<char> {
- match self.low {
- Some(c) => {
- self.low = None;
- Some(c)
- }
- None => self.iter.next_back().map(|b| {
- let (high, low) = byte_to_hex_chars(b);
- self.low = Some(low);
- high
- }),
+ let mut iter = HexToBytesIter::new(hex).unwrap().rev();
+ for i in (0..=bytes.len()).rev() {
+ assert_eq!(iter.len(), i);
+ let _ = iter.next();
}
}
-}
-impl<I> ExactSizeIterator for BytesToHexIter<I>
-where
- I: ExactSizeIterator + Iterator<Item = u8>,
-{
- #[inline]
- fn len(&self) -> usize { self.iter.len() * 2 }
-}
-
-impl<I> FusedIterator for BytesToHexIter<I> where I: FusedIterator + Iterator<Item = u8> {}
-
-/// Returns the (high, low) hex characters encoding `b`.
-fn byte_to_hex_chars(b: u8) -> (char, char) {
- const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
+ #[test]
+ fn hex_to_digits_size_hint() {
+ let hex = "deadbeef";
+ let iter = HexDigitsIter::new_unchecked(hex.as_bytes());
+ // HexDigitsIter yields two digits at a time `[u8; 2]`.
+ assert_eq!(iter.size_hint(), (4, Some(4)));
+ }
- let high = HEX_TABLE[usize::from(b >> 4)];
- let low = HEX_TABLE[usize::from(b & 0b00001111)];
+ #[test]
+ fn hex_to_bytes_size_hint() {
+ let hex = "deadbeef";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ assert_eq!(iter.size_hint(), (4, Some(4)));
+ }
- (char::from(high), char::from(low))
-}
+ #[test]
+ fn hex_to_bytes_slice_drain() {
+ let hex = "deadbeef";
+ let want = [0xde, 0xad, 0xbe, 0xef];
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let mut got = [0u8; 4];
+ iter.drain_to_slice(&mut got).unwrap();
+ assert_eq!(got, want);
+
+ let hex = "";
+ let want = [];
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let mut got = [];
+ iter.drain_to_slice(&mut got).unwrap();
+ assert_eq!(got, want);
+ }
-#[cfg(test)]
-mod tests {
- use super::*;
+ #[test]
+ #[should_panic]
+ // Don't test panic message because it is from `debug_assert`.
+ #[allow(clippy::should_panic_without_expect)]
+ fn hex_to_bytes_slice_drain_panic_empty() {
+ let hex = "deadbeef";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let mut got = [];
+ iter.drain_to_slice(&mut got).unwrap();
+ }
#[test]
- fn encode_byte() {
- let tcs =
- vec![(0x00, ('0', '0')), (0x0a, ('0', 'a')), (0xad, ('a', 'd')), (0xff, ('f', 'f'))];
- for (b, (high, low)) in tcs {
- assert_eq!(byte_to_hex_chars(b), (high, low));
- }
- assert_eq!(byte_to_hex_chars(0x00), ('0', '0'));
- assert_eq!(byte_to_hex_chars(0x0a), ('0', 'a'));
- assert_eq!(byte_to_hex_chars(0xad), ('a', 'd'));
- assert_eq!(byte_to_hex_chars(0xff), ('f', 'f'));
+ #[should_panic]
+ // Don't test panic message because it is from `debug_assert`.
+ #[allow(clippy::should_panic_without_expect)]
+ fn hex_to_bytes_slice_drain_panic_too_small() {
+ let hex = "deadbeef";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let mut got = [0u8; 3];
+ iter.drain_to_slice(&mut got).unwrap();
}
#[test]
- fn decode_iter_forward() {
+ #[should_panic]
+ // Don't test panic message because it is from `debug_assert`.
+ #[allow(clippy::should_panic_without_expect)]
+ fn hex_to_bytes_slice_drain_panic_too_big() {
let hex = "deadbeef";
- let bytes = [0xde, 0xad, 0xbe, 0xef];
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let mut got = [0u8; 5];
+ iter.drain_to_slice(&mut got).unwrap();
+ }
- for (i, b) in HexToBytesIter::new(hex).unwrap().enumerate() {
- assert_eq!(b.unwrap(), bytes[i]);
- }
+ #[test]
+ fn hex_to_bytes_slice_drain_first_char_error() {
+ let hex = "geadbeef";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let mut got = [0u8; 4];
+ assert_eq!(
+ iter.drain_to_slice(&mut got).unwrap_err(),
+ InvalidCharError { invalid: b'g', pos: 0 }
+ );
}
#[test]
- fn decode_iter_backward() {
- let hex = "deadbeef";
- let bytes = [0xef, 0xbe, 0xad, 0xde];
+ fn hex_to_bytes_slice_drain_middle_char_error() {
+ let hex = "deadgeef";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let mut got = [0u8; 4];
+ assert_eq!(
+ iter.drain_to_slice(&mut got).unwrap_err(),
+ InvalidCharError { invalid: b'g', pos: 4 }
+ );
+ }
- for (i, b) in HexToBytesIter::new(hex).unwrap().rev().enumerate() {
- assert_eq!(b.unwrap(), bytes[i]);
- }
+ #[test]
+ fn hex_to_bytes_slice_drain_end_char_error() {
+ let hex = "deadbeeg";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let mut got = [0u8; 4];
+ assert_eq!(
+ iter.drain_to_slice(&mut got).unwrap_err(),
+ InvalidCharError { invalid: b'g', pos: 7 }
+ );
}
+ #[cfg(feature = "alloc")]
#[test]
- fn encode_iter() {
- let bytes = [0xde, 0xad, 0xbe, 0xef];
+ fn hex_to_bytes_vec_drain() {
let hex = "deadbeef";
-
- for (i, c) in BytesToHexIter::new(bytes.iter().cloned()).enumerate() {
- assert_eq!(c, hex.chars().nth(i).unwrap());
- }
+ let want = [0xde, 0xad, 0xbe, 0xef];
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let got = iter.drain_to_vec().unwrap();
+ assert_eq!(got, want);
+
+ let hex = "";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ let got = iter.drain_to_vec().unwrap();
+ assert!(got.is_empty());
}
+ #[cfg(feature = "alloc")]
#[test]
- fn encode_iter_backwards() {
- let bytes = [0xde, 0xad, 0xbe, 0xef];
- let hex = "efbeadde";
+ fn hex_to_bytes_vec_drain_first_char_error() {
+ let hex = "geadbeef";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ assert_eq!(iter.drain_to_vec().unwrap_err(), InvalidCharError { invalid: b'g', pos: 0 });
+ }
- for (i, c) in BytesToHexIter::new(bytes.iter().cloned()).rev().enumerate() {
- assert_eq!(c, hex.chars().nth(i).unwrap());
- }
+ #[cfg(feature = "alloc")]
+ #[test]
+ fn hex_to_bytes_vec_drain_middle_char_error() {
+ let hex = "deadgeef";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ assert_eq!(iter.drain_to_vec().unwrap_err(), InvalidCharError { invalid: b'g', pos: 4 });
}
+ #[cfg(feature = "alloc")]
#[test]
- fn roundtrip_forward() {
- let hex = "deadbeefcafebabe";
- let bytes_iter = HexToBytesIter::new(hex).unwrap().map(|res| res.unwrap());
- let got = BytesToHexIter::new(bytes_iter).collect::<String>();
- assert_eq!(got, hex);
+ fn hex_to_bytes_vec_drain_end_char_error() {
+ let hex = "deadbeeg";
+ let iter = HexToBytesIter::new_unchecked(hex);
+ assert_eq!(iter.drain_to_vec().unwrap_err(), InvalidCharError { invalid: b'g', pos: 7 });
}
#[test]
- fn roundtrip_backward() {
- let hex = "deadbeefcafebabe";
- let bytes_iter = HexToBytesIter::new(hex).unwrap().rev().map(|res| res.unwrap());
- let got = BytesToHexIter::new(bytes_iter).rev().collect::<String>();
- assert_eq!(got, hex);
+ #[cfg(feature = "std")]
+ fn hex_to_bytes_iter_read() {
+ use std::io::Read;
+
+ let hex = "deadbeef";
+ let mut iter = HexToBytesIter::new(hex).unwrap();
+ let mut buf = [0u8; 4];
+ let bytes_read = iter.read(&mut buf).unwrap();
+ assert_eq!(bytes_read, 4);
+ assert_eq!(buf, [0xde, 0xad, 0xbe, 0xef]);
+
+ let hex = "deadbeef";
+ let mut iter = HexToBytesIter::new(hex).unwrap();
+ let mut buf = [0u8; 2];
+ let bytes_read = iter.read(&mut buf).unwrap();
+ assert_eq!(bytes_read, 2);
+ assert_eq!(buf, [0xde, 0xad]);
+
+ let hex = "deadbeef";
+ let mut iter = HexToBytesIter::new(hex).unwrap();
+ let mut buf = [0u8; 6];
+ let bytes_read = iter.read(&mut buf).unwrap();
+ assert_eq!(bytes_read, 4);
+ assert_eq!(buf[..4], [0xde, 0xad, 0xbe, 0xef]);
+
+ let hex = "deadbeefXX";
+ let mut iter = HexToBytesIter::new(hex).unwrap();
+ let mut buf = [0u8; 6];
+ let err = iter.read(&mut buf).unwrap_err();
+ assert_eq!(err.kind(), io::ErrorKind::InvalidData);
}
}
diff --git a/external/vendor/hex-conservative/src/lib.rs b/external/vendor/hex-conservative/src/lib.rs
index 4939821..f082f97 100644
--- a/external/vendor/hex-conservative/src/lib.rs
+++ b/external/vendor/hex-conservative/src/lib.rs
@@ -4,156 +4,117 @@
//!
//! General purpose hex encoding/decoding library with a conservative MSRV and dependency policy.
//!
-//! ## Basic Usage
-//! ```
-//! # #[cfg(feature = "alloc")] {
-//! // In your manifest use the `package` key to improve import ergonomics.
-//! // hex = { package = "hex-conservative", version = "*" }
-//! # use hex_conservative as hex; // No need for this if using `package` as above.
-//! use hex::prelude::*;
+//! ## Stabilization strategy
//!
-//! // Decode an arbitrary length hex string into a vector.
-//! let v = Vec::from_hex("deadbeef").expect("valid hex digits");
-//! // Or a known length hex string into a fixed size array.
-//! let a = <[u8; 4]>::from_hex("deadbeef").expect("valid length and valid hex digits");
+//! Because downstream crates may need to return hex errors in their APIs and they need to be
+//! stabilized soon, this crate only exposes the errors and two basic decoding functions. This
+//! should already help with the vast majority of the cases and we're sufficiently confident that
+//! these errors won't have a breaking change any time soon (possibly never).
//!
-//! // We support `LowerHex` and `UpperHex` out of the box for `[u8]` slices.
-//! println!("An array as lower hex: {:x}", a.as_hex());
-//! // And for vecs since `Vec` derefs to byte slice.
-//! println!("A vector as upper hex: {:X}", v.as_hex());
+//! If you're writing a binary you don't need to worry about any of this and just use the unstable
+//! version for now. If you're writing a library you should use these stable errors in the API but
+//! you may internally depend on the unstable crate version to get the advanced features that won't
+//! affect your API. This way your API can stabilize before all features in this crate are fully
+//! stable and you still can use all of them.
//!
-//! // Allocate a new string (also `to_upper_hex_string`).
-//! let s = v.to_lower_hex_string();
+//! ## Crate feature flags
//!
-//! // Please note, mixed case strings will still parse successfully but we only
-//! // support displaying hex in a single case.
-//! assert_eq!(
-//! Vec::from_hex("dEaDbEeF").expect("valid mixed case hex digits"),
-//! Vec::from_hex("deadbeef").expect("valid hex digits"),
-//! );
-//! # }
-//! ```
+//! * `std` - enables the standard library, on by default.
+//! * `alloc` - enables features that require allocation such as decoding into `Vec<u8>`, implied
+//! by `std`.
+//! * `newer-rust-version` - enables Rust version detection and thus newer features, may add
+//! dependency on a feature detection crate to reduce compile times. This feature is expected to
+//! do nothing once the native detection is in Rust and our MSRV is at least that version. We may
+//! also remove the feature gate in 2.0 with semver trick once that happens.
+//!
+//! ## MSRV policy
+//!
+//! The MSRV of the crate is currently 1.63.0 and we don't intend to bump it until the newer Rust
+//! version is at least two years old and also included in Debian stable (1.63 is in Debian 12 at
+//! the moment).
+//!
+//! Note though that the dependencies may have looser policy. This is not considered
+//! breaking/wrong - you would just need to pin them in `Cargo.lock` (not `.toml`).
-#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
+#![no_std]
// Experimental features we need.
#![cfg_attr(docsrs, feature(doc_cfg))]
-#![cfg_attr(docsrs, feature(doc_auto_cfg))]
// Coding conventions
#![warn(missing_docs)]
+#[cfg(feature = "std")]
+extern crate std;
+
#[cfg(feature = "alloc")]
+#[allow(unused_imports)] // false positive regarding macro
+#[macro_use]
extern crate alloc;
#[doc(hidden)]
pub mod _export {
- /// A re-export of core::*
+ /// A re-export of `core::*`.
pub mod _core {
pub use core::*;
}
}
-pub mod buf_encoder;
-pub mod display;
pub mod error;
mod iter;
-pub mod parse;
-#[cfg(feature = "serde")]
-pub mod serde;
-/// Re-exports of the common crate traits.
-pub mod prelude {
- #[doc(inline)]
- pub use crate::{display::DisplayHex, parse::FromHex};
-}
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
-pub(crate) use table::Table;
+use crate::iter::HexToBytesIter;
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
pub use self::{
- display::DisplayHex,
- error::{OddLengthStringError, HexToBytesError, HexToArrayError, InvalidCharError},
- iter::{BytesToHexIter, HexToBytesIter, HexSliceToBytesIter},
- parse::FromHex,
+ error::{
+ DecodeFixedLengthBytesError, DecodeVariableLengthBytesError,
+ },
};
-/// Possible case of hex.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum Case {
- /// Produce lower-case chars (`[0-9a-f]`).
- ///
- /// This is the default.
- Lower,
-
- /// Produce upper-case chars (`[0-9A-F]`).
- Upper,
-}
-
-impl Default for Case {
- #[inline]
- fn default() -> Self { Case::Lower }
-}
-
-impl Case {
- /// Returns the encoding table.
- ///
- /// The returned table may only contain displayable ASCII chars.
- #[inline]
- #[rustfmt::skip]
- pub(crate) fn table(self) -> &'static Table {
- match self {
- Case::Lower => &Table::LOWER,
- Case::Upper => &Table::UPPER,
- }
- }
+/// Decodes a hex string with variable length.
+///
+/// The length of the returned `Vec` is determined by the length of the input, meaning all even
+/// lengths of the input string are allowed. If you know the required length at compile time using
+/// [`decode_to_array`] is most likely a better choice.
+///
+/// # Errors
+///
+/// Returns an error if `hex` contains invalid characters or doesn't have even length.
+#[cfg(feature = "alloc")]
+pub fn decode_to_vec(hex: &str) -> Result<Vec<u8>, DecodeVariableLengthBytesError> {
+ Ok(HexToBytesIter::new(hex)?.drain_to_vec()?)
}
-/// Correctness boundary for `Table`.
-mod table {
- use arrayvec::ArrayString;
-
- /// Table of hex chars.
- //
- // Correctness invariant: each byte in the table must be ASCII.
- pub(crate) struct Table([u8; 16]);
-
- impl Table {
- pub(crate) const LOWER: Self = Table([
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd',
- b'e', b'f',
- ]);
- pub(crate) const UPPER: Self = Table([
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D',
- b'E', b'F',
- ]);
-
- /// Encodes single byte as two ASCII chars using the given table.
- ///
- /// The function guarantees only returning values from the provided table.
- #[inline]
- pub(crate) fn byte_to_hex(&self, byte: u8) -> ArrayString<2> {
- let left = self.0[usize::from(byte.wrapping_shr(4))];
- let right = self.0[usize::from(byte & 0x0F)];
-
- ArrayString::from_byte_string(&[left, right]).expect("Table only contains valid ASCII")
- }
+/// Decodes a hex string with an expected length known at compile time.
+///
+/// If you don't know the required length at compile time you need to use [`decode_to_vec`]
+/// instead.
+///
+/// # Errors
+///
+/// Returns an error if `hex` contains invalid characters or has incorrect length. (Should be
+/// `N * 2`.)
+pub fn decode_to_array<const N: usize>(hex: &str) -> Result<[u8; N], DecodeFixedLengthBytesError> {
+ if hex.len() == N * 2 {
+ let mut ret = [0u8; N];
+ // checked above
+ HexToBytesIter::new_unchecked(hex).drain_to_slice(&mut ret)?;
+ Ok(ret)
+ } else {
+ Err(error::InvalidLengthError { invalid: hex.len(), expected: 2 * N }.into())
}
}
-/// Quick and dirty macro for parsing hex in tests.
-///
-/// For improved ergonomics import with: `use hex_conservative::test_hex_unwrap as hex;`
-#[macro_export]
-macro_rules! test_hex_unwrap (($hex:expr) => (<Vec<u8> as $crate::FromHex>::from_hex($hex).unwrap()));
-
#[cfg(test)]
+#[cfg(feature = "alloc")]
mod tests {
- use crate::test_hex_unwrap as hex;
-
#[test]
fn parse_hex_into_vector() {
- let got = hex!("deadbeef");
+ let got = crate::decode_to_vec("deadbeef").unwrap();
let want = vec![0xde, 0xad, 0xbe, 0xef];
- assert_eq!(got, want)
+ assert_eq!(got, want);
}
}
diff --git a/external/vendor/hex-conservative/src/parse.rs b/external/vendor/hex-conservative/src/parse.rs
deleted file mode 100644
index fe8e98d..0000000
--- a/external/vendor/hex-conservative/src/parse.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-// SPDX-License-Identifier: CC0-1.0
-
-//! Hex encoding and decoding.
-
-use core::{fmt, str};
-
-use arrayvec::ArrayVec;
-
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use crate::aWhy this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.