summaryrefslogtreecommitdiffstats
path: root/vendor/faster-hex
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/faster-hex
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/faster-hex')
-rw-r--r--vendor/faster-hex/.cargo-checksum.json1
-rw-r--r--vendor/faster-hex/Cargo.toml67
-rw-r--r--vendor/faster-hex/LICENSE21
-rw-r--r--vendor/faster-hex/LICENSE-THIRD-PARTY/Rust Project Developers25
-rw-r--r--vendor/faster-hex/LICENSE-THIRD-PARTY/fast-hex21
-rw-r--r--vendor/faster-hex/README.md114
-rw-r--r--vendor/faster-hex/src/decode.rs530
-rw-r--r--vendor/faster-hex/src/encode.rs254
-rw-r--r--vendor/faster-hex/src/error.rs30
-rw-r--r--vendor/faster-hex/src/lib.rs216
-rw-r--r--vendor/faster-hex/src/serde.rs372
11 files changed, 1651 insertions, 0 deletions
diff --git a/vendor/faster-hex/.cargo-checksum.json b/vendor/faster-hex/.cargo-checksum.json
new file mode 100644
index 000000000..c1efdc840
--- /dev/null
+++ b/vendor/faster-hex/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"393bee41f638fa483744cdf8efcaa0d70df5c9917ace40db6d3164411e41fead","LICENSE":"7e4baa202160a035c769bb83bd994222c74f479ec582624e3aedaa8f553481c7","LICENSE-THIRD-PARTY/Rust Project Developers":"29662666b44dff84977b46e05642cdef910bc3a93a17b5fd86e632bafa59cf21","LICENSE-THIRD-PARTY/fast-hex":"7c652d12760975f519e979b099e40f9c0868c1139b231e780cea69b2a3fd6656","README.md":"14bf30faaad09c315642b1913b9ebd9f4ae740bf76773b249e411b45379a6917","src/decode.rs":"93bb5d2a734510aae223f67098abc76ea236496d7e898ede076ada8d40a21e24","src/encode.rs":"0574ec4c39984565472b2e01b1978b6e5472d3459a6917e8723c510bd509a0d7","src/error.rs":"2b3fca5f4ea575a87c81053029f01bac4a334abc3b6f0b84dd210f4a933af894","src/lib.rs":"6b72b5816aaff727bdca4370b11297b54e970d5b18c1ed0e914ca7d6d53beb18","src/serde.rs":"46e123d026d9827ea89cd45825943abda617f18294a8490228d1a628ec750e40"},"package":"239f7bfb930f820ab16a9cd95afc26f88264cf6905c960b340a615384aa3338a"} \ No newline at end of file
diff --git a/vendor/faster-hex/Cargo.toml b/vendor/faster-hex/Cargo.toml
new file mode 100644
index 000000000..57618bc2d
--- /dev/null
+++ b/vendor/faster-hex/Cargo.toml
@@ -0,0 +1,67 @@
+# 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 = "faster-hex"
+version = "0.8.1"
+authors = ["zhangsoledad <787953403@qq.com>"]
+exclude = [
+ "afl/*",
+ "benches/*",
+ "fuzz/*",
+ "CHANGELOG.md",
+]
+description = "Fast hex encoding."
+homepage = "https://github.com/NervosFoundation/faster-hex"
+readme = "README.md"
+keywords = [
+ "simd",
+ "hex",
+ "no-std",
+]
+license = "MIT"
+repository = "https://github.com/NervosFoundation/faster-hex"
+
+[dependencies.serde]
+version = "1.0"
+optional = true
+
+[dev-dependencies.bytes]
+version = "1.4.0"
+
+[dev-dependencies.criterion]
+version = "0.3"
+
+[dev-dependencies.hex]
+version = "0.3.2"
+
+[dev-dependencies.proptest]
+version = "1.0"
+
+[dev-dependencies.rustc-hex]
+version = "1.0"
+
+[dev-dependencies.serde]
+version = "1.0"
+features = ["derive"]
+
+[dev-dependencies.serde_json]
+version = "1.0"
+
+[features]
+alloc = []
+default = [
+ "std",
+ "serde",
+]
+serde = ["dep:serde"]
+std = ["alloc"]
diff --git a/vendor/faster-hex/LICENSE b/vendor/faster-hex/LICENSE
new file mode 100644
index 000000000..b37bc2c2d
--- /dev/null
+++ b/vendor/faster-hex/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Nervos Foundation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/faster-hex/LICENSE-THIRD-PARTY/Rust Project Developers b/vendor/faster-hex/LICENSE-THIRD-PARTY/Rust Project Developers
new file mode 100644
index 000000000..52d82415d
--- /dev/null
+++ b/vendor/faster-hex/LICENSE-THIRD-PARTY/Rust Project Developers
@@ -0,0 +1,25 @@
+Copyright (c) 2017 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/vendor/faster-hex/LICENSE-THIRD-PARTY/fast-hex b/vendor/faster-hex/LICENSE-THIRD-PARTY/fast-hex
new file mode 100644
index 000000000..285bc059d
--- /dev/null
+++ b/vendor/faster-hex/LICENSE-THIRD-PARTY/fast-hex
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Zach Bjornson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/faster-hex/README.md b/vendor/faster-hex/README.md
new file mode 100644
index 000000000..4234be587
--- /dev/null
+++ b/vendor/faster-hex/README.md
@@ -0,0 +1,114 @@
+# faster-hex
+
+[![License]](#license)
+[![crate-badge]](https://crates.io/crates/faster-hex)
+
+[crate-badge]: https://img.shields.io/crates/v/faster-hex.svg
+[license]: https://img.shields.io/badge/License-MIT-green.svg
+
+This program implements hex encoding a slice into a predetermined
+destination using various different instruction sets.
+
+## Benchmark
+
+### Running
+Runs benchmark
+```
+cargo bench
+```
+
+### Results
+Machine: MacBook Pro (Early 2015) (2.7 GHz Intel Core i5)
+
+Rust: rustc 1.31.0 (abe02cefd 2018-12-04)
+
+Compare with [hex](https://crates.io/crates/hex):
+
+* Encoding ~10x over
+* Decoding ~10x over
+
+Compare with [rustc-hex](https://crates.io/crates/rustc-hex):
+
+* Encoding ~2.5x over
+* Decoding ~7x over
+
+## Examples
+Encode to hex
+
+```rust
+use faster_hex::hex_string;
+
+let result = hex_string(b"Hello world!");
+assert_eq!(result, "48656c6c6f20776f726c6421");
+```
+Encode to upper case hex
+```rust
+use faster_hex::hex_string_upper;
+
+let result = hex_string_upper(b"Hello world!");
+assert_eq!(result, "48656C6C6F20776F726C6421");
+```
+
+Decode
+```rust
+use faster_hex::hex_decode;
+
+let src = b"48656c6c6f20776f726c6421";
+let mut dst = vec![0; src.len() / 2];
+hex_decode(src, &mut dst).unwrap();
+assert_eq!(dst, b"Hello world!");
+```
+Decode with case check
+```rust
+use faster_hex::{hex_decode_with_case, CheckCase};
+
+let src = b"48656c6c6f20776f726c6421";
+let mut dst = vec![0; src.len() / 2];
+
+assert!(hex_decode_with_case(src, &mut dst, CheckCase::Lower).is_ok());
+assert_eq!(dst, b"Hello world!");
+
+assert!(hex_decode_with_case(src, &mut dst, CheckCase::None).is_ok());
+assert_eq!(dst, b"Hello world!");
+
+assert!(hex_decode_with_case(src, &mut dst, CheckCase::Upper).is_err());
+```
+
+Serde feature
+```rust
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+struct Simple {
+ #[serde(with = "faster_hex")]
+ foo: Vec<u8>,
+ #[serde(with = "faster_hex::nopfx_lowercase")]
+ bar: Vec<u8>,
+}
+```
+
+
+## Notice
+
+Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.
+
+MINOR version when make incompatible API changes before 1.0.0.
+
+
+## License
+
+This project is licensed under the [MIT license](LICENSE).
+
+### Third party software
+
+This product includes copies and modifications of software developed by third parties:
+
+* [src/encode.rs](src/encode.rs) is based on
+ [stdsimd](https://github.com/rust-lang-nursery/stdsimd), licensed
+ under the MIT license or the Apache License (Version 2.0).
+* [src/decode.rs](src/decode.rs) avx2 decode is modified from [fast-hex](https://github.com/zbjornson/fast-hex)
+
+See the source code files for more details.
+
+Copies of third party licenses can be found in [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY).
diff --git a/vendor/faster-hex/src/decode.rs b/vendor/faster-hex/src/decode.rs
new file mode 100644
index 000000000..5b7b440eb
--- /dev/null
+++ b/vendor/faster-hex/src/decode.rs
@@ -0,0 +1,530 @@
+// avx2 decode modified from https://github.com/zbjornson/fast-hex/blob/master/src/hex.cc
+
+#[cfg(target_arch = "x86")]
+use core::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use core::arch::x86_64::*;
+
+use crate::error::Error;
+
+const NIL: u8 = u8::MAX;
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+const T_MASK: i32 = 65535;
+
+const fn init_unhex_array(check_case: CheckCase) -> [u8; 256] {
+ let mut arr = [0; 256];
+ let mut i = 0;
+ while i < 256 {
+ arr[i] = match i as u8 {
+ b'0'..=b'9' => i as u8 - b'0',
+ b'a'..=b'f' => match check_case {
+ CheckCase::Lower | CheckCase::None => i as u8 - b'a' + 10,
+ _ => NIL,
+ },
+ b'A'..=b'F' => match check_case {
+ CheckCase::Upper | CheckCase::None => i as u8 - b'A' + 10,
+ _ => NIL,
+ },
+ _ => NIL,
+ };
+ i += 1;
+ }
+ arr
+}
+
+const fn init_unhex4_array(check_case: CheckCase) -> [u8; 256] {
+ let unhex_arr = init_unhex_array(check_case);
+
+ let mut unhex4_arr = [NIL; 256];
+ let mut i = 0;
+ while i < 256 {
+ if unhex_arr[i] != NIL {
+ unhex4_arr[i] = unhex_arr[i] << 4;
+ }
+ i += 1;
+ }
+ unhex4_arr
+}
+
+// ASCII -> hex
+pub(crate) static UNHEX: [u8; 256] = init_unhex_array(CheckCase::None);
+
+// ASCII -> hex, lower case
+pub(crate) static UNHEX_LOWER: [u8; 256] = init_unhex_array(CheckCase::Lower);
+
+// ASCII -> hex, upper case
+pub(crate) static UNHEX_UPPER: [u8; 256] = init_unhex_array(CheckCase::Upper);
+
+// ASCII -> hex << 4
+pub(crate) static UNHEX4: [u8; 256] = init_unhex4_array(CheckCase::None);
+
+const _0213: i32 = 0b11011000;
+
+// lower nibble
+#[inline]
+fn unhex_b(x: usize) -> u8 {
+ UNHEX[x]
+}
+
+// upper nibble, logically equivalent to unhex_b(x) << 4
+#[inline]
+fn unhex_a(x: usize) -> u8 {
+ UNHEX4[x]
+}
+
+#[inline]
+#[target_feature(enable = "avx2")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+unsafe fn unhex_avx2(value: __m256i) -> __m256i {
+ let sr6 = _mm256_srai_epi16(value, 6);
+ let and15 = _mm256_and_si256(value, _mm256_set1_epi16(0xf));
+ let mul = _mm256_maddubs_epi16(sr6, _mm256_set1_epi16(9));
+ _mm256_add_epi16(mul, and15)
+}
+
+// (a << 4) | b;
+#[inline]
+#[target_feature(enable = "avx2")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+unsafe fn nib2byte_avx2(a1: __m256i, b1: __m256i, a2: __m256i, b2: __m256i) -> __m256i {
+ let a4_1 = _mm256_slli_epi16(a1, 4);
+ let a4_2 = _mm256_slli_epi16(a2, 4);
+ let a4orb_1 = _mm256_or_si256(a4_1, b1);
+ let a4orb_2 = _mm256_or_si256(a4_2, b2);
+ let pck1 = _mm256_packus_epi16(a4orb_1, a4orb_2);
+ _mm256_permute4x64_epi64(pck1, _0213)
+}
+
+/// Check if the input is valid hex bytes slice
+pub fn hex_check(src: &[u8]) -> bool {
+ hex_check_with_case(src, CheckCase::None)
+}
+
+/// Check if the input is valid hex bytes slice with case check
+pub fn hex_check_with_case(src: &[u8], check_case: CheckCase) -> bool {
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ {
+ match crate::vectorization_support() {
+ crate::Vectorization::AVX2 | crate::Vectorization::SSE41 => unsafe {
+ hex_check_sse_with_case(src, check_case)
+ },
+ crate::Vectorization::None => hex_check_fallback_with_case(src, check_case),
+ }
+ }
+
+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+ hex_check_fallback_with_case(src, check_case)
+}
+
+/// Check if the input is valid hex bytes slice
+pub fn hex_check_fallback(src: &[u8]) -> bool {
+ hex_check_fallback_with_case(src, CheckCase::None)
+}
+
+/// Check if the input is valid hex bytes slice with case check
+pub fn hex_check_fallback_with_case(src: &[u8], check_case: CheckCase) -> bool {
+ match check_case {
+ CheckCase::None => src.iter().all(|&x| UNHEX[x as usize] != NIL),
+ CheckCase::Lower => src.iter().all(|&x| UNHEX_LOWER[x as usize] != NIL),
+ CheckCase::Upper => src.iter().all(|&x| UNHEX_UPPER[x as usize] != NIL),
+ }
+}
+
+/// # Safety
+/// Check if a byte slice is valid.
+#[target_feature(enable = "sse4.1")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub unsafe fn hex_check_sse(src: &[u8]) -> bool {
+ hex_check_sse_with_case(src, CheckCase::None)
+}
+
+#[derive(Eq, PartialEq)]
+pub enum CheckCase {
+ None,
+ Lower,
+ Upper,
+}
+
+/// # Safety
+/// Check if a byte slice is valid on given check_case.
+#[target_feature(enable = "sse4.1")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub unsafe fn hex_check_sse_with_case(mut src: &[u8], check_case: CheckCase) -> bool {
+ let ascii_zero = _mm_set1_epi8((b'0' - 1) as i8);
+ let ascii_nine = _mm_set1_epi8((b'9' + 1) as i8);
+ let ascii_ua = _mm_set1_epi8((b'A' - 1) as i8);
+ let ascii_uf = _mm_set1_epi8((b'F' + 1) as i8);
+ let ascii_la = _mm_set1_epi8((b'a' - 1) as i8);
+ let ascii_lf = _mm_set1_epi8((b'f' + 1) as i8);
+
+ while src.len() >= 16 {
+ let unchecked = _mm_loadu_si128(src.as_ptr() as *const _);
+
+ let gt0 = _mm_cmpgt_epi8(unchecked, ascii_zero);
+ let lt9 = _mm_cmplt_epi8(unchecked, ascii_nine);
+ let valid_digit = _mm_and_si128(gt0, lt9);
+
+ let (valid_la_lf, valid_ua_uf) = match check_case {
+ CheckCase::None => {
+ let gtua = _mm_cmpgt_epi8(unchecked, ascii_ua);
+ let ltuf = _mm_cmplt_epi8(unchecked, ascii_uf);
+
+ let gtla = _mm_cmpgt_epi8(unchecked, ascii_la);
+ let ltlf = _mm_cmplt_epi8(unchecked, ascii_lf);
+
+ (
+ Some(_mm_and_si128(gtla, ltlf)),
+ Some(_mm_and_si128(gtua, ltuf)),
+ )
+ }
+ CheckCase::Lower => {
+ let gtla = _mm_cmpgt_epi8(unchecked, ascii_la);
+ let ltlf = _mm_cmplt_epi8(unchecked, ascii_lf);
+
+ (Some(_mm_and_si128(gtla, ltlf)), None)
+ }
+ CheckCase::Upper => {
+ let gtua = _mm_cmpgt_epi8(unchecked, ascii_ua);
+ let ltuf = _mm_cmplt_epi8(unchecked, ascii_uf);
+ (None, Some(_mm_and_si128(gtua, ltuf)))
+ }
+ };
+
+ let valid_letter = match (valid_la_lf, valid_ua_uf) {
+ (Some(valid_lower), Some(valid_upper)) => _mm_or_si128(valid_lower, valid_upper),
+ (Some(valid_lower), None) => valid_lower,
+ (None, Some(valid_upper)) => valid_upper,
+ _ => unreachable!(),
+ };
+
+ let ret = _mm_movemask_epi8(_mm_or_si128(valid_digit, valid_letter));
+
+ if ret != T_MASK {
+ return false;
+ }
+
+ src = &src[16..];
+ }
+ hex_check_fallback_with_case(src, check_case)
+}
+
+/// Hex decode src into dst.
+/// The length of src must be even and not zero.
+/// The length of dst must be at least src.len() / 2.
+pub fn hex_decode(src: &[u8], dst: &mut [u8]) -> Result<(), Error> {
+ hex_decode_with_case(src, dst, CheckCase::None)
+}
+
+/// Hex decode src into dst.
+/// The length of src must be even, and it's allowed to decode a zero length src.
+/// The length of dst must be at least src.len() / 2.
+/// when check_case is CheckCase::Lower, the hex string must be lower case.
+/// when check_case is CheckCase::Upper, the hex string must be upper case.
+/// when check_case is CheckCase::None, the hex string can be lower case or upper case.
+pub fn hex_decode_with_case(
+ src: &[u8],
+ dst: &mut [u8],
+ check_case: CheckCase,
+) -> Result<(), Error> {
+ if src.len() & 1 != 0 {
+ return Err(Error::InvalidLength(src.len()));
+ }
+
+ let expect_dst_len = src.len().checked_div(2).unwrap();
+
+ if dst.len() < expect_dst_len {
+ return Err(Error::InvalidLength(dst.len()));
+ }
+ if !hex_check_with_case(src, check_case) {
+ return Err(Error::InvalidChar);
+ }
+ hex_decode_unchecked(src, dst);
+ Ok(())
+}
+
+pub fn hex_decode_unchecked(src: &[u8], dst: &mut [u8]) {
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ {
+ match crate::vectorization_support() {
+ crate::Vectorization::AVX2 => unsafe { hex_decode_avx2(src, dst) },
+ crate::Vectorization::None | crate::Vectorization::SSE41 => {
+ hex_decode_fallback(src, dst)
+ }
+ }
+ }
+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+ hex_decode_fallback(src, dst);
+}
+
+#[target_feature(enable = "avx2")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+unsafe fn hex_decode_avx2(mut src: &[u8], mut dst: &mut [u8]) {
+ // 0, -1, 2, -1, 4, -1, 6, -1, 8, -1, 10, -1, 12, -1, 14, -1,
+ // 0, -1, 2, -1, 4, -1, 6, -1, 8, -1, 10, -1, 12, -1, 14, -1
+ let mask_a = _mm256_setr_epi8(
+ 0, -1, 2, -1, 4, -1, 6, -1, 8, -1, 10, -1, 12, -1, 14, -1, 0, -1, 2, -1, 4, -1, 6, -1, 8,
+ -1, 10, -1, 12, -1, 14, -1,
+ );
+
+ // 1, -1, 3, -1, 5, -1, 7, -1, 9, -1, 11, -1, 13, -1, 15, -1,
+ // 1, -1, 3, -1, 5, -1, 7, -1, 9, -1, 11, -1, 13, -1, 15, -1
+ let mask_b = _mm256_setr_epi8(
+ 1, -1, 3, -1, 5, -1, 7, -1, 9, -1, 11, -1, 13, -1, 15, -1, 1, -1, 3, -1, 5, -1, 7, -1, 9,
+ -1, 11, -1, 13, -1, 15, -1,
+ );
+
+ while dst.len() >= 32 {
+ let av1 = _mm256_loadu_si256(src.as_ptr() as *const _);
+ let av2 = _mm256_loadu_si256(src[32..].as_ptr() as *const _);
+
+ let mut a1 = _mm256_shuffle_epi8(av1, mask_a);
+ let mut b1 = _mm256_shuffle_epi8(av1, mask_b);
+ let mut a2 = _mm256_shuffle_epi8(av2, mask_a);
+ let mut b2 = _mm256_shuffle_epi8(av2, mask_b);
+
+ a1 = unhex_avx2(a1);
+ a2 = unhex_avx2(a2);
+ b1 = unhex_avx2(b1);
+ b2 = unhex_avx2(b2);
+
+ let bytes = nib2byte_avx2(a1, b1, a2, b2);
+
+ //dst does not need to be aligned on any particular boundary
+ _mm256_storeu_si256(dst.as_mut_ptr() as *mut _, bytes);
+ dst = &mut dst[32..];
+ src = &src[64..];
+ }
+ hex_decode_fallback(src, dst)
+}
+
+pub fn hex_decode_fallback(src: &[u8], dst: &mut [u8]) {
+ for (slot, bytes) in dst.iter_mut().zip(src.chunks_exact(2)) {
+ let a = unhex_a(bytes[0] as usize);
+ let b = unhex_b(bytes[1] as usize);
+ *slot = a | b;
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::decode::NIL;
+ use crate::{
+ decode::{
+ hex_check_fallback, hex_check_fallback_with_case, hex_decode_fallback, CheckCase,
+ },
+ encode::hex_string,
+ };
+ use proptest::proptest;
+
+ fn _test_decode_fallback(s: &String) {
+ let len = s.as_bytes().len();
+ let mut dst = Vec::with_capacity(len);
+ dst.resize(len, 0);
+
+ let hex_string = hex_string(s.as_bytes());
+
+ hex_decode_fallback(hex_string.as_bytes(), &mut dst);
+
+ assert_eq!(&dst[..], s.as_bytes());
+ }
+
+ proptest! {
+ #[test]
+ fn test_decode_fallback(ref s in ".+") {
+ _test_decode_fallback(s);
+ }
+ }
+
+ fn _test_check_fallback_true(s: &String) {
+ assert!(hex_check_fallback(s.as_bytes()));
+ match (
+ s.contains(char::is_lowercase),
+ s.contains(char::is_uppercase),
+ ) {
+ (true, true) => {
+ assert!(!hex_check_fallback_with_case(
+ s.as_bytes(),
+ CheckCase::Lower
+ ));
+ assert!(!hex_check_fallback_with_case(
+ s.as_bytes(),
+ CheckCase::Upper
+ ));
+ }
+ (true, false) => {
+ assert!(hex_check_fallback_with_case(s.as_bytes(), CheckCase::Lower));
+ assert!(!hex_check_fallback_with_case(
+ s.as_bytes(),
+ CheckCase::Upper
+ ));
+ }
+ (false, true) => {
+ assert!(!hex_check_fallback_with_case(
+ s.as_bytes(),
+ CheckCase::Lower
+ ));
+ assert!(hex_check_fallback_with_case(s.as_bytes(), CheckCase::Upper));
+ }
+ (false, false) => {
+ assert!(hex_check_fallback_with_case(s.as_bytes(), CheckCase::Lower));
+ assert!(hex_check_fallback_with_case(s.as_bytes(), CheckCase::Upper));
+ }
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn test_check_fallback_true(ref s in "[0-9a-fA-F]+") {
+ _test_check_fallback_true(s);
+ }
+ }
+
+ fn _test_check_fallback_false(s: &String) {
+ assert!(!hex_check_fallback(s.as_bytes()));
+ assert!(!hex_check_fallback_with_case(
+ s.as_bytes(),
+ CheckCase::Upper
+ ));
+ assert!(!hex_check_fallback_with_case(
+ s.as_bytes(),
+ CheckCase::Lower
+ ));
+ }
+
+ proptest! {
+ #[test]
+ fn test_check_fallback_false(ref s in ".{16}[^0-9a-fA-F]+") {
+ _test_check_fallback_false(s);
+ }
+ }
+
+ #[test]
+ fn test_init_static_array_is_right() {
+ static OLD_UNHEX: [u8; 256] = [
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, NIL, NIL, NIL, NIL, NIL, NIL, NIL, 10, 11, 12, 13, 14, 15, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, 10, 11, 12, 13, 14, 15, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ ];
+
+ static OLD_UNHEX4: [u8; 256] = [
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, 0, 16, 32, 48,
+ 64, 80, 96, 112, 128, 144, NIL, NIL, NIL, NIL, NIL, NIL, NIL, 160, 176, 192, 208, 224,
+ 240, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, 160, 176, 192, 208, 224, 240, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ ];
+
+ assert_eq!(OLD_UNHEX, crate::decode::UNHEX);
+ assert_eq!(OLD_UNHEX4, crate::decode::UNHEX4);
+ }
+}
+
+#[cfg(all(test, any(target_arch = "x86", target_arch = "x86_64")))]
+mod test_sse {
+ use crate::decode::{
+ hex_check, hex_check_fallback, hex_check_fallback_with_case, hex_check_sse,
+ hex_check_sse_with_case, hex_check_with_case, hex_decode, hex_decode_unchecked,
+ hex_decode_with_case, CheckCase,
+ };
+ use proptest::proptest;
+
+ fn _test_check_sse_with_case(s: &String, check_case: CheckCase, expect_result: bool) {
+ if is_x86_feature_detected!("sse4.1") {
+ assert_eq!(
+ unsafe { hex_check_sse_with_case(s.as_bytes(), check_case) },
+ expect_result
+ )
+ }
+ }
+
+ fn _test_check_sse_true(s: &String) {
+ if is_x86_feature_detected!("sse4.1") {
+ assert!(unsafe { hex_check_sse(s.as_bytes()) });
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn test_check_sse_true(ref s in "([0-9a-fA-F][0-9a-fA-F])+") {
+ _test_check_sse_true(s);
+ _test_check_sse_with_case(s, CheckCase::None, true);
+ match (s.contains(char::is_lowercase), s.contains(char::is_uppercase)){
+ (true, true) => {
+ _test_check_sse_with_case(s, CheckCase::Lower, false);
+ _test_check_sse_with_case(s, CheckCase::Upper, false);
+ },
+ (true, false) => {
+ _test_check_sse_with_case(s, CheckCase::Lower, true);
+ _test_check_sse_with_case(s, CheckCase::Upper, false);
+ },
+ (false, true) => {
+ _test_check_sse_with_case(s, CheckCase::Lower, false);
+ _test_check_sse_with_case(s, CheckCase::Upper, true);
+ },
+ (false, false) => {
+ _test_check_sse_with_case(s, CheckCase::Lower, true);
+ _test_check_sse_with_case(s, CheckCase::Upper, true);
+ }
+ }
+ }
+ }
+
+ fn _test_check_sse_false(s: &String) {
+ if is_x86_feature_detected!("sse4.1") {
+ assert!(!unsafe { hex_check_sse(s.as_bytes()) });
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn test_check_sse_false(ref s in ".{16}[^0-9a-fA-F]+") {
+ _test_check_sse_false(s);
+ _test_check_sse_with_case(s, CheckCase::None, false);
+ _test_check_sse_with_case(s, CheckCase::Lower, false);
+ _test_check_sse_with_case(s, CheckCase::Upper, false);
+ }
+ }
+
+ #[test]
+ fn test_decode_zero_length_src_should_be_ok() {
+ let src = b"";
+ let mut dst = [0u8; 10];
+ assert!(hex_decode(src, &mut dst).is_ok());
+ assert!(hex_decode_with_case(src, &mut dst, CheckCase::None).is_ok());
+ assert!(hex_check(src));
+ assert!(hex_check_with_case(src, CheckCase::None));
+ assert!(hex_check_fallback(src));
+ assert!(hex_check_fallback_with_case(src, CheckCase::None));
+
+ if is_x86_feature_detected!("sse4.1") {
+ assert!(unsafe { hex_check_sse_with_case(src, CheckCase::None) });
+ assert!(unsafe { hex_check_sse(src) });
+ }
+
+ // this function have no return value, so we just execute it and expect no panic
+ hex_decode_unchecked(src, &mut dst);
+ }
+}
diff --git a/vendor/faster-hex/src/encode.rs b/vendor/faster-hex/src/encode.rs
new file mode 100644
index 000000000..ff56836bd
--- /dev/null
+++ b/vendor/faster-hex/src/encode.rs
@@ -0,0 +1,254 @@
+#[cfg(target_arch = "x86")]
+use core::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use core::arch::x86_64::*;
+
+#[cfg(feature = "alloc")]
+use alloc::{string::String, vec};
+
+use crate::error::Error;
+
+static TABLE_LOWER: &[u8] = b"0123456789abcdef";
+static TABLE_UPPER: &[u8] = b"0123456789ABCDEF";
+
+#[cfg(any(feature = "alloc", test))]
+fn hex_string_custom_case(src: &[u8], upper_case: bool) -> String {
+ let mut buffer = vec![0; src.len() * 2];
+ if upper_case {
+ hex_encode_upper(src, &mut buffer).expect("hex_string");
+ } else {
+ hex_encode(src, &mut buffer).expect("hex_string");
+ }
+
+ if cfg!(debug_assertions) {
+ String::from_utf8(buffer).unwrap()
+ } else {
+ // Saftey: We just wrote valid utf8 hex string into the dst
+ unsafe { String::from_utf8_unchecked(buffer) }
+ }
+}
+
+#[cfg(any(feature = "alloc", test))]
+pub fn hex_string(src: &[u8]) -> String {
+ hex_string_custom_case(src, false)
+}
+
+#[cfg(any(feature = "alloc", test))]
+pub fn hex_string_upper(src: &[u8]) -> String {
+ hex_string_custom_case(src, true)
+}
+
+pub fn hex_encode_custom<'a>(
+ src: &[u8],
+ dst: &'a mut [u8],
+ upper_case: bool,
+) -> Result<&'a mut str, Error> {
+ unsafe fn mut_str(buffer: &mut [u8]) -> &mut str {
+ if cfg!(debug_assertions) {
+ core::str::from_utf8_mut(buffer).unwrap()
+ } else {
+ core::str::from_utf8_unchecked_mut(buffer)
+ }
+ }
+
+ let expect_dst_len = src
+ .len()
+ .checked_mul(2)
+ .ok_or(Error::InvalidLength(src.len()))?;
+ if dst.len() < expect_dst_len {
+ return Err(Error::InvalidLength(expect_dst_len));
+ }
+
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ {
+ match crate::vectorization_support() {
+ crate::Vectorization::AVX2 => unsafe { hex_encode_avx2(src, dst, upper_case) },
+ crate::Vectorization::SSE41 => unsafe { hex_encode_sse41(src, dst, upper_case) },
+ crate::Vectorization::None => hex_encode_custom_case_fallback(src, dst, upper_case),
+ }
+ // Safety: We just wrote valid utf8 hex string into the dst
+ return Ok(unsafe { mut_str(dst) });
+ }
+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+ {
+ hex_encode_custom_case_fallback(src, dst, upper_case);
+ // Saftey: We just wrote valid utf8 hex string into the dst
+ Ok(unsafe { mut_str(dst) })
+ }
+}
+
+/// Hex encode src into dst.
+/// The length of dst must be at least src.len() * 2.
+pub fn hex_encode<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a mut str, Error> {
+ hex_encode_custom(src, dst, false)
+}
+
+pub fn hex_encode_upper<'a>(src: &[u8], dst: &'a mut [u8]) -> Result<&'a mut str, Error> {
+ hex_encode_custom(src, dst, true)
+}
+
+#[deprecated(since = "0.3.0", note = "please use `hex_encode` instead")]
+pub fn hex_to(src: &[u8], dst: &mut [u8]) -> Result<(), Error> {
+ hex_encode(src, dst).map(|_| ())
+}
+
+#[target_feature(enable = "avx2")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+unsafe fn hex_encode_avx2(mut src: &[u8], dst: &mut [u8], upper_case: bool) {
+ let ascii_zero = _mm256_set1_epi8(b'0' as i8);
+ let nines = _mm256_set1_epi8(9);
+ let ascii_a = if upper_case {
+ _mm256_set1_epi8((b'A' - 9 - 1) as i8)
+ } else {
+ _mm256_set1_epi8((b'a' - 9 - 1) as i8)
+ };
+ let and4bits = _mm256_set1_epi8(0xf);
+
+ let mut i = 0_isize;
+ while src.len() >= 32 {
+ // https://stackoverflow.com/questions/47425851/whats-the-difference-between-mm256-lddqu-si256-and-mm256-loadu-si256
+ let invec = _mm256_loadu_si256(src.as_ptr() as *const _);
+
+ let masked1 = _mm256_and_si256(invec, and4bits);
+ let masked2 = _mm256_and_si256(_mm256_srli_epi64(invec, 4), and4bits);
+
+ // return 0xff corresponding to the elements > 9, or 0x00 otherwise
+ let cmpmask1 = _mm256_cmpgt_epi8(masked1, nines);
+ let cmpmask2 = _mm256_cmpgt_epi8(masked2, nines);
+
+ // add '0' or the offset depending on the masks
+ let masked1 = _mm256_add_epi8(masked1, _mm256_blendv_epi8(ascii_zero, ascii_a, cmpmask1));
+ let masked2 = _mm256_add_epi8(masked2, _mm256_blendv_epi8(ascii_zero, ascii_a, cmpmask2));
+
+ // interleave masked1 and masked2 bytes
+ let res1 = _mm256_unpacklo_epi8(masked2, masked1);
+ let res2 = _mm256_unpackhi_epi8(masked2, masked1);
+
+ // Store everything into the right destination now
+ let base = dst.as_mut_ptr().offset(i * 2);
+ let base1 = base.offset(0) as *mut _;
+ let base2 = base.offset(16) as *mut _;
+ let base3 = base.offset(32) as *mut _;
+ let base4 = base.offset(48) as *mut _;
+ _mm256_storeu2_m128i(base3, base1, res1);
+ _mm256_storeu2_m128i(base4, base2, res2);
+ src = &src[32..];
+ i += 32;
+ }
+
+ let i = i as usize;
+ hex_encode_sse41(src, &mut dst[i * 2..], upper_case);
+}
+
+// copied from https://github.com/Matherunner/bin2hex-sse/blob/master/base16_sse4.cpp
+#[target_feature(enable = "sse4.1")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+unsafe fn hex_encode_sse41(mut src: &[u8], dst: &mut [u8], upper_case: bool) {
+ let ascii_zero = _mm_set1_epi8(b'0' as i8);
+ let nines = _mm_set1_epi8(9);
+ let ascii_a = if upper_case {
+ _mm_set1_epi8((b'A' - 9 - 1) as i8)
+ } else {
+ _mm_set1_epi8((b'a' - 9 - 1) as i8)
+ };
+ let and4bits = _mm_set1_epi8(0xf);
+
+ let mut i = 0_isize;
+ while src.len() >= 16 {
+ let invec = _mm_loadu_si128(src.as_ptr() as *const _);
+
+ let masked1 = _mm_and_si128(invec, and4bits);
+ let masked2 = _mm_and_si128(_mm_srli_epi64(invec, 4), and4bits);
+
+ // return 0xff corresponding to the elements > 9, or 0x00 otherwise
+ let cmpmask1 = _mm_cmpgt_epi8(masked1, nines);
+ let cmpmask2 = _mm_cmpgt_epi8(masked2, nines);
+
+ // add '0' or the offset depending on the masks
+ let masked1 = _mm_add_epi8(masked1, _mm_blendv_epi8(ascii_zero, ascii_a, cmpmask1));
+ let masked2 = _mm_add_epi8(masked2, _mm_blendv_epi8(ascii_zero, ascii_a, cmpmask2));
+
+ // interleave masked1 and masked2 bytes
+ let res1 = _mm_unpacklo_epi8(masked2, masked1);
+ let res2 = _mm_unpackhi_epi8(masked2, masked1);
+
+ _mm_storeu_si128(dst.as_mut_ptr().offset(i * 2) as *mut _, res1);
+ _mm_storeu_si128(dst.as_mut_ptr().offset(i * 2 + 16) as *mut _, res2);
+ src = &src[16..];
+ i += 16;
+ }
+
+ let i = i as usize;
+ hex_encode_custom_case_fallback(src, &mut dst[i * 2..], upper_case);
+}
+
+#[inline]
+fn hex_lower(byte: u8) -> u8 {
+ TABLE_LOWER[byte as usize]
+}
+
+#[inline]
+fn hex_upper(byte: u8) -> u8 {
+ TABLE_UPPER[byte as usize]
+}
+
+fn hex_encode_custom_case_fallback(src: &[u8], dst: &mut [u8], upper_case: bool) {
+ if upper_case {
+ for (byte, slots) in src.iter().zip(dst.chunks_exact_mut(2)) {
+ slots[0] = hex_upper((*byte >> 4) & 0xf);
+ slots[1] = hex_upper(*byte & 0xf);
+ }
+ } else {
+ for (byte, slots) in src.iter().zip(dst.chunks_exact_mut(2)) {
+ slots[0] = hex_lower((*byte >> 4) & 0xf);
+ slots[1] = hex_lower(*byte & 0xf);
+ }
+ }
+}
+
+pub fn hex_encode_fallback(src: &[u8], dst: &mut [u8]) {
+ hex_encode_custom_case_fallback(src, dst, false)
+}
+
+pub fn hex_encode_upper_fallback(src: &[u8], dst: &mut [u8]) {
+ hex_encode_custom_case_fallback(src, dst, true)
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::encode::{hex_encode, hex_encode_custom_case_fallback};
+
+ use crate::hex_encode_fallback;
+ use core::str;
+ use proptest::proptest;
+
+ fn _test_encode_fallback(s: &String, upper_case: bool) {
+ let mut buffer = vec![0; s.as_bytes().len() * 2];
+ hex_encode_custom_case_fallback(s.as_bytes(), &mut buffer, upper_case);
+
+ let encode = unsafe { str::from_utf8_unchecked(&buffer[..s.as_bytes().len() * 2]) };
+ if upper_case {
+ assert_eq!(encode, hex::encode_upper(s));
+ } else {
+ assert_eq!(encode, hex::encode(s));
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn test_encode_fallback(ref s in ".*") {
+ _test_encode_fallback(s, true);
+ _test_encode_fallback(s, false);
+ }
+ }
+
+ #[test]
+ fn test_encode_zero_length_src_should_be_ok() {
+ let src = b"";
+ let mut dst = [0u8; 10];
+ assert!(hex_encode(src, &mut dst).is_ok());
+
+ // this function have no return value, so we just execute it and expect no panic
+ hex_encode_fallback(src, &mut dst);
+ }
+}
diff --git a/vendor/faster-hex/src/error.rs b/vendor/faster-hex/src/error.rs
new file mode 100644
index 000000000..d6cf5f249
--- /dev/null
+++ b/vendor/faster-hex/src/error.rs
@@ -0,0 +1,30 @@
+#[derive(Clone, Copy)]
+pub enum Error {
+ InvalidChar,
+ InvalidLength(usize),
+}
+
+impl ::core::fmt::Debug for Error {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ match *self {
+ Error::InvalidLength(len) => write!(f, "Invalid input length {len}"),
+ Error::InvalidChar => write!(f, "Invalid character"),
+ }
+ }
+}
+
+impl ::core::fmt::Display for Error {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ ::core::fmt::Debug::fmt(&self, f)
+ }
+}
+
+#[cfg(feature = "std")]
+impl ::std::error::Error for Error {
+ fn description(&self) -> &str {
+ match *self {
+ Error::InvalidChar => "invalid character",
+ Error::InvalidLength(_) => "invalid length",
+ }
+ }
+}
diff --git a/vendor/faster-hex/src/lib.rs b/vendor/faster-hex/src/lib.rs
new file mode 100644
index 000000000..86a357714
--- /dev/null
+++ b/vendor/faster-hex/src/lib.rs
@@ -0,0 +1,216 @@
+#![cfg_attr(not(any(test, feature = "std")), no_std)]
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+
+mod decode;
+mod encode;
+mod error;
+
+#[cfg(feature = "serde")]
+mod serde;
+
+pub use crate::decode::{
+ hex_check, hex_check_fallback, hex_check_with_case, hex_decode, hex_decode_fallback,
+ hex_decode_unchecked,
+};
+pub use crate::encode::{
+ hex_encode, hex_encode_fallback, hex_encode_upper, hex_encode_upper_fallback,
+};
+#[cfg(feature = "alloc")]
+pub use crate::encode::{hex_string, hex_string_upper};
+
+pub use crate::error::Error;
+
+#[cfg(feature = "serde")]
+pub use crate::serde::{
+ deserialize, nopfx_ignorecase, nopfx_lowercase, nopfx_uppercase, serialize, withpfx_ignorecase,
+ withpfx_lowercase, withpfx_uppercase,
+};
+
+#[allow(deprecated)]
+pub use crate::encode::hex_to;
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub use crate::decode::{hex_check_sse, hex_check_sse_with_case};
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub(crate) enum Vectorization {
+ None = 0,
+ SSE41 = 1,
+ AVX2 = 2,
+}
+
+#[inline(always)]
+pub(crate) fn vectorization_support() -> Vectorization {
+ #[cfg(all(any(target_arch = "x86", target_arch = "x86_64")))]
+ {
+ use core::sync::atomic::{AtomicU8, Ordering};
+ static FLAGS: AtomicU8 = AtomicU8::new(u8::MAX);
+
+ // We're OK with relaxed, worst case scenario multiple threads checked the CPUID.
+ let current_flags = FLAGS.load(Ordering::Relaxed);
+ // u8::MAX means uninitialized.
+ if current_flags != u8::MAX {
+ return match current_flags {
+ 0 => Vectorization::None,
+ 1 => Vectorization::SSE41,
+ 2 => Vectorization::AVX2,
+ _ => unreachable!(),
+ };
+ }
+
+ let val = unsafe { vectorization_support_no_cache_x86() };
+
+ FLAGS.store(val as u8, Ordering::Relaxed);
+ return val;
+ }
+ #[allow(unreachable_code)]
+ Vectorization::None
+}
+
+// We enable xsave so it can inline the _xgetbv call.
+#[target_feature(enable = "xsave")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[cold]
+unsafe fn vectorization_support_no_cache_x86() -> Vectorization {
+ #[cfg(target_arch = "x86")]
+ use core::arch::x86::{__cpuid_count, _xgetbv};
+ #[cfg(target_arch = "x86_64")]
+ use core::arch::x86_64::{__cpuid_count, _xgetbv};
+
+ // SGX doesn't support CPUID,
+ // If there's no SSE there might not be CPUID and there's no SSE4.1/AVX2
+ if cfg!(target_env = "sgx") || !cfg!(target_feature = "sse") {
+ return Vectorization::None;
+ }
+
+ let proc_info_ecx = __cpuid_count(1, 0).ecx;
+ let have_sse4 = (proc_info_ecx >> 19) & 1 == 1;
+ // If there's no SSE4 there can't be AVX2.
+ if !have_sse4 {
+ return Vectorization::None;
+ }
+ let have_xsave = (proc_info_ecx >> 26) & 1 == 1;
+ let have_osxsave = (proc_info_ecx >> 27) & 1 == 1;
+ let have_avx = (proc_info_ecx >> 27) & 1 == 1;
+ if have_xsave && have_osxsave && have_avx {
+ let xcr0 = _xgetbv(0);
+ let os_avx_support = xcr0 & 6 == 6;
+ if os_avx_support {
+ let extended_features_ebx = __cpuid_count(7, 0).ebx;
+ let have_avx2 = (extended_features_ebx >> 5) & 1 == 1;
+ if have_avx2 {
+ return Vectorization::AVX2;
+ }
+ }
+ }
+ Vectorization::SSE41
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::decode::{hex_decode, hex_decode_with_case, CheckCase};
+ use crate::encode::{hex_encode, hex_string};
+ use crate::{hex_encode_upper, hex_string_upper, vectorization_support, Vectorization};
+ use proptest::proptest;
+
+ #[test]
+ fn test_feature_detection() {
+ let vector_support = vectorization_support();
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ {
+ match vector_support {
+ Vectorization::AVX2 => assert!(is_x86_feature_detected!("avx2")),
+ Vectorization::SSE41 => assert!(is_x86_feature_detected!("sse4.1")),
+ Vectorization::None => assert!(
+ !cfg!(target_feature = "sse")
+ || !is_x86_feature_detected!("avx2") && !is_x86_feature_detected!("sse4.1")
+ ),
+ }
+ }
+ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+ assert_eq!(vector_support, Vectorization::None);
+ }
+
+ fn _test_hex_encode(s: &String) {
+ let mut buffer = vec![0; s.as_bytes().len() * 2];
+ {
+ let encode = &*hex_encode(s.as_bytes(), &mut buffer).unwrap();
+
+ let hex_string = hex_string(s.as_bytes());
+
+ assert_eq!(encode, hex::encode(s));
+ assert_eq!(hex_string, hex::encode(s));
+ }
+
+ {
+ let encode_upper = &*hex_encode_upper(s.as_bytes(), &mut buffer).unwrap();
+
+ let hex_string_upper = hex_string_upper(s.as_bytes());
+
+ assert_eq!(encode_upper, hex::encode_upper(s));
+ assert_eq!(hex_string_upper, hex::encode_upper(s));
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn test_hex_encode(ref s in ".*") {
+ _test_hex_encode(s);
+ }
+ }
+
+ fn _test_hex_decode(s: &String) {
+ let len = s.as_bytes().len();
+
+ {
+ let mut dst = Vec::with_capacity(len);
+ dst.resize(len, 0);
+ let hex_string = hex_string(s.as_bytes());
+
+ hex_decode(hex_string.as_bytes(), &mut dst).unwrap();
+
+ hex_decode_with_case(hex_string.as_bytes(), &mut dst, CheckCase::Lower).unwrap();
+
+ assert_eq!(&dst[..], s.as_bytes());
+ }
+ {
+ let mut dst = Vec::with_capacity(len);
+ dst.resize(len, 0);
+ let hex_string_upper = hex_string_upper(s.as_bytes());
+
+ hex_decode_with_case(hex_string_upper.as_bytes(), &mut dst, CheckCase::Upper).unwrap();
+
+ assert_eq!(&dst[..], s.as_bytes());
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn test_hex_decode(ref s in ".+") {
+ _test_hex_decode(s);
+ }
+ }
+
+ fn _test_hex_decode_check(s: &String, ok: bool) {
+ let len = s.as_bytes().len();
+ let mut dst = Vec::with_capacity(len / 2);
+ dst.resize(len / 2, 0);
+ assert!(hex_decode(s.as_bytes(), &mut dst).is_ok() == ok);
+ }
+
+ proptest! {
+ #[test]
+ fn test_hex_decode_check(ref s in "([0-9a-fA-F][0-9a-fA-F])+") {
+ _test_hex_decode_check(s, true);
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn test_hex_decode_check_odd(ref s in "[0-9a-fA-F]{11}") {
+ _test_hex_decode_check(s, false);
+ }
+ }
+}
diff --git a/vendor/faster-hex/src/serde.rs b/vendor/faster-hex/src/serde.rs
new file mode 100644
index 000000000..eeea57751
--- /dev/null
+++ b/vendor/faster-hex/src/serde.rs
@@ -0,0 +1,372 @@
+#![warn(missing_docs)]
+
+use std::iter::FromIterator;
+
+mod internal {
+ use crate::{
+ decode::{hex_decode_with_case, CheckCase},
+ encode::hex_encode_custom,
+ };
+ use alloc::borrow::Cow;
+ use serde::{de::Error, Deserializer, Serializer};
+ use std::iter::FromIterator;
+
+ pub(crate) fn serialize<S, T>(
+ data: T,
+ serializer: S,
+ with_prefix: bool,
+ case: CheckCase,
+ ) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ T: AsRef<[u8]>,
+ {
+ let src: &[u8] = data.as_ref();
+
+ let mut dst_length = data.as_ref().len() << 1;
+ if with_prefix {
+ dst_length += 2;
+ }
+
+ let mut dst = vec![0u8; dst_length];
+ let mut dst_start = 0;
+ if with_prefix {
+ dst[0] = b'0';
+ dst[1] = b'x';
+
+ dst_start = 2;
+ }
+
+ hex_encode_custom(src, &mut dst[dst_start..], matches!(case, CheckCase::Upper))
+ .map_err(serde::ser::Error::custom)?;
+ serializer.serialize_str(unsafe { ::std::str::from_utf8_unchecked(&dst) })
+ }
+
+ pub(crate) fn deserialize<'de, D, T>(
+ deserializer: D,
+ with_prefix: bool,
+ check_case: CheckCase,
+ ) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>,
+ T: FromIterator<u8>,
+ {
+ let raw_src: Cow<str> = serde::Deserialize::deserialize(deserializer)?;
+ if with_prefix && !raw_src.starts_with("0x") {
+ return Err(D::Error::custom("invalid prefix".to_string()));
+ }
+
+ let src: &[u8] = {
+ if with_prefix {
+ raw_src[2..].as_bytes()
+ } else {
+ raw_src.as_bytes()
+ }
+ };
+
+ if src.len() & 1 != 0 {
+ return Err(D::Error::custom("invalid length".to_string()));
+ }
+
+ // we have already checked src's length, so src's length is a even integer
+ let mut dst = vec![0; src.len() >> 1];
+ hex_decode_with_case(src, &mut dst, check_case)
+ .map_err(|e| Error::custom(format!("{:?}", e)))?;
+ Ok(dst.into_iter().collect())
+ }
+}
+
+/// Serde: Serialize with 0x-prefix and ignore case
+pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
+where
+ S: serde::Serializer,
+ T: AsRef<[u8]>,
+{
+ withpfx_ignorecase::serialize(data, serializer)
+}
+
+/// Serde: Deserialize with 0x-prefix and ignore case
+pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+where
+ D: serde::Deserializer<'de>,
+ T: FromIterator<u8>,
+{
+ withpfx_ignorecase::deserialize(deserializer)
+}
+
+/// Generate module with serde methods
+macro_rules! faster_hex_serde_macros {
+ ($mod_name:ident, $with_pfx:expr, $check_case:expr) => {
+ /// Serialize and deserialize with or without 0x-prefix,
+ /// and lowercase or uppercase or ignorecase
+ pub mod $mod_name {
+ use crate::decode::CheckCase;
+ use crate::serde::internal;
+ use std::iter::FromIterator;
+
+ /// Serializes `data` as hex string
+ pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ T: AsRef<[u8]>,
+ {
+ internal::serialize(data, serializer, $with_pfx, $check_case)
+ }
+
+ /// Deserializes a hex string into raw bytes.
+ pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ T: FromIterator<u8>,
+ {
+ internal::deserialize(deserializer, $with_pfx, $check_case)
+ }
+ }
+ };
+}
+
+// /// Serialize with 0x-prefix and lowercase
+// /// When deserialize, expect 0x-prefix and don't care case
+faster_hex_serde_macros!(withpfx_ignorecase, true, CheckCase::None);
+// /// Serialize without 0x-prefix and lowercase
+// /// When deserialize, expect without 0x-prefix and don't care case
+faster_hex_serde_macros!(nopfx_ignorecase, false, CheckCase::None);
+// /// Serialize with 0x-prefix and lowercase
+// /// When deserialize, expect with 0x-prefix and lower case
+faster_hex_serde_macros!(withpfx_lowercase, true, CheckCase::Lower);
+// /// Serialize without 0x-prefix and lowercase
+// /// When deserialize, expect without 0x-prefix and lower case
+faster_hex_serde_macros!(nopfx_lowercase, false, CheckCase::Lower);
+
+// /// Serialize with 0x-prefix and upper case
+// /// When deserialize, expect with 0x-prefix and upper case
+faster_hex_serde_macros!(withpfx_uppercase, true, CheckCase::Upper);
+// /// Serialize without 0x-prefix and upper case
+// /// When deserialize, expect without 0x-prefix and upper case
+faster_hex_serde_macros!(nopfx_uppercase, false, CheckCase::Upper);
+
+#[cfg(test)]
+mod tests {
+ use super::{
+ nopfx_ignorecase, nopfx_lowercase, nopfx_uppercase, withpfx_ignorecase, withpfx_lowercase,
+ withpfx_uppercase,
+ };
+ use crate as faster_hex;
+ use bytes::Bytes;
+ use proptest::proptest;
+ use serde::{Deserialize, Serialize};
+
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct Simple {
+ #[serde(with = "faster_hex")]
+ bar: Vec<u8>,
+ }
+
+ #[test]
+ fn test_deserialize_escaped() {
+ // 0x03 but escaped.
+ let x: Simple = serde_json::from_str(
+ r#"{
+ "bar": "\u0030x\u00303"
+ }"#,
+ )
+ .unwrap();
+ assert_eq!(x.bar, b"\x03");
+ }
+
+ fn _test_simple(src: &str) {
+ let simple = Simple { bar: src.into() };
+ let result = serde_json::to_string(&simple);
+ assert!(result.is_ok());
+ let result = result.unwrap();
+
+ // #[serde(with = "faster_hex")] should result with 0x prefix
+ assert!(result.starts_with(r#"{"bar":"0x"#));
+
+ // #[serde(with = "faster_hex")] shouldn't contains uppercase
+ assert!(result[7..].chars().all(|c| !c.is_uppercase()));
+
+ let decode_simple = serde_json::from_str::<Simple>(&result);
+ assert!(decode_simple.is_ok());
+ assert_eq!(decode_simple.unwrap(), simple);
+ }
+
+ proptest! {
+ #[test]
+ fn test_simple(ref s in ".*") {
+ _test_simple(s);
+ }
+ }
+
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct Foo {
+ #[serde(with = "nopfx_lowercase")]
+ bar_nopfx_lowercase_vec: Vec<u8>,
+ #[serde(with = "nopfx_lowercase")]
+ bar_nopfx_lowercase_bytes: Bytes,
+
+ #[serde(with = "withpfx_lowercase")]
+ bar_withpfx_lowercase_vec: Vec<u8>,
+ #[serde(with = "withpfx_lowercase")]
+ bar_withpfx_lowercase_bytes: Bytes,
+
+ #[serde(with = "nopfx_uppercase")]
+ bar_nopfx_uppercase_vec: Vec<u8>,
+ #[serde(with = "nopfx_uppercase")]
+ bar_nopfx_uppercase_bytes: Bytes,
+
+ #[serde(with = "withpfx_uppercase")]
+ bar_withpfx_uppercase_vec: Vec<u8>,
+ #[serde(with = "withpfx_uppercase")]
+ bar_withpfx_uppercase_bytes: Bytes,
+
+ #[serde(with = "withpfx_ignorecase")]
+ bar_withpfx_ignorecase_vec: Vec<u8>,
+ #[serde(with = "withpfx_ignorecase")]
+ bar_withpfx_ignorecase_bytes: Bytes,
+
+ #[serde(with = "nopfx_ignorecase")]
+ bar_nopfx_ignorecase_vec: Vec<u8>,
+ #[serde(with = "nopfx_ignorecase")]
+ bar_nopfx_ignorecase_bytes: Bytes,
+ }
+
+ #[test]
+ fn test_serde_default() {
+ {
+ let foo_defuault = Foo {
+ bar_nopfx_lowercase_vec: vec![],
+ bar_nopfx_lowercase_bytes: Default::default(),
+ bar_withpfx_lowercase_vec: vec![],
+ bar_withpfx_lowercase_bytes: Default::default(),
+ bar_nopfx_uppercase_vec: vec![],
+ bar_nopfx_uppercase_bytes: Default::default(),
+ bar_withpfx_uppercase_vec: vec![],
+ bar_withpfx_uppercase_bytes: Default::default(),
+ bar_withpfx_ignorecase_vec: vec![],
+ bar_withpfx_ignorecase_bytes: Default::default(),
+ bar_nopfx_ignorecase_vec: vec![],
+ bar_nopfx_ignorecase_bytes: Default::default(),
+ };
+ let serde_result = serde_json::to_string(&foo_defuault).unwrap();
+ let expect = "{\"bar_nopfx_lowercase_vec\":\"\",\"bar_nopfx_lowercase_bytes\":\"\",\"bar_withpfx_lowercase_vec\":\"0x\",\"bar_withpfx_lowercase_bytes\":\"0x\",\"bar_nopfx_uppercase_vec\":\"\",\"bar_nopfx_uppercase_bytes\":\"\",\"bar_withpfx_uppercase_vec\":\"0x\",\"bar_withpfx_uppercase_bytes\":\"0x\",\"bar_withpfx_ignorecase_vec\":\"0x\",\"bar_withpfx_ignorecase_bytes\":\"0x\",\"bar_nopfx_ignorecase_vec\":\"\",\"bar_nopfx_ignorecase_bytes\":\"\"}";
+ assert_eq!(serde_result, expect);
+
+ let foo_src: Foo = serde_json::from_str(&serde_result).unwrap();
+ assert_eq!(foo_defuault, foo_src);
+ }
+ }
+
+ fn _test_serde(src: &str) {
+ let foo = Foo {
+ bar_nopfx_lowercase_vec: Vec::from(src),
+ bar_nopfx_lowercase_bytes: Bytes::from(Vec::from(src)),
+ bar_withpfx_lowercase_vec: Vec::from(src),
+ bar_withpfx_lowercase_bytes: Bytes::from(Vec::from(src)),
+ bar_nopfx_uppercase_vec: Vec::from(src),
+ bar_nopfx_uppercase_bytes: Bytes::from(Vec::from(src)),
+ bar_withpfx_uppercase_vec: Vec::from(src),
+ bar_withpfx_uppercase_bytes: Bytes::from(Vec::from(src)),
+
+ bar_withpfx_ignorecase_vec: Vec::from(src),
+ bar_withpfx_ignorecase_bytes: Bytes::from(Vec::from(src)),
+ bar_nopfx_ignorecase_vec: Vec::from(src),
+ bar_nopfx_ignorecase_bytes: Bytes::from(Vec::from(src)),
+ };
+ let hex_str = hex::encode(src);
+ let hex_str_upper = hex::encode_upper(src);
+ let serde_result = serde_json::to_string(&foo).unwrap();
+
+ let expect = format!("{{\"bar_nopfx_lowercase_vec\":\"{}\",\"bar_nopfx_lowercase_bytes\":\"{}\",\"bar_withpfx_lowercase_vec\":\"0x{}\",\"bar_withpfx_lowercase_bytes\":\"0x{}\",\"bar_nopfx_uppercase_vec\":\"{}\",\"bar_nopfx_uppercase_bytes\":\"{}\",\"bar_withpfx_uppercase_vec\":\"0x{}\",\"bar_withpfx_uppercase_bytes\":\"0x{}\",\"bar_withpfx_ignorecase_vec\":\"0x{}\",\"bar_withpfx_ignorecase_bytes\":\"0x{}\",\"bar_nopfx_ignorecase_vec\":\"{}\",\"bar_nopfx_ignorecase_bytes\":\"{}\"}}",
+ hex_str,
+ hex_str,
+ hex_str,
+ hex_str,
+ hex_str_upper,
+ hex_str_upper,
+ hex_str_upper,
+ hex_str_upper,
+ hex_str,
+ hex_str,
+ hex_str,
+ hex_str,
+
+ );
+ assert_eq!(serde_result, expect);
+
+ let foo_src: Foo = serde_json::from_str(&serde_result).unwrap();
+ assert_eq!(foo, foo_src);
+ }
+
+ proptest! {
+ #[test]
+ fn test_serde(ref s in ".*") {
+ _test_serde(s);
+ }
+ }
+
+ fn _test_serde_deserialize(src: &str) {
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct FooNoPfxLower {
+ #[serde(with = "nopfx_lowercase")]
+ bar: Vec<u8>,
+ }
+
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct FooWithPfxLower {
+ #[serde(with = "withpfx_lowercase")]
+ bar: Vec<u8>,
+ }
+
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct FooNoPfxUpper {
+ #[serde(with = "nopfx_uppercase")]
+ bar: Vec<u8>,
+ }
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct FooWithPfxUpper {
+ #[serde(with = "withpfx_uppercase")]
+ bar: Vec<u8>,
+ }
+
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct FooNoPfxIgnoreCase {
+ #[serde(with = "nopfx_ignorecase")]
+ bar: Vec<u8>,
+ }
+ #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+ struct FooWithPfxIgnoreCase {
+ #[serde(with = "withpfx_ignorecase")]
+ bar: Vec<u8>,
+ }
+
+ {
+ let hex_foo = serde_json::to_string(&FooNoPfxLower { bar: src.into() }).unwrap();
+ let foo_pfx: serde_json::Result<FooWithPfxLower> = serde_json::from_str(&hex_foo);
+ // assert foo_pfx is Error, and contains "invalid prefix"
+ assert!(foo_pfx.is_err());
+ assert!(foo_pfx.unwrap_err().to_string().contains("invalid prefix"));
+ }
+
+ {
+ let foo_lower = serde_json::to_string(&FooNoPfxLower { bar: src.into() }).unwrap();
+ let foo_upper_result: serde_json::Result<FooNoPfxUpper> =
+ serde_json::from_str(&foo_lower);
+ if hex::encode(src).contains(char::is_lowercase) {
+ // FooNoPfxLower's foo field is lowercase, so we can't deserialize it to FooNoPfxUpper
+ assert!(foo_upper_result.is_err());
+ assert!(foo_upper_result
+ .unwrap_err()
+ .to_string()
+ .contains("Invalid character"));
+ }
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn test_serde_deserialize(ref s in ".*") {
+ _test_serde_deserialize(s);
+ }
+ }
+}