1b0988833a Remove `ToHex` (Martin Habovstiak)

Pull request description:

  The `ToHex` trait was replaced by either simple `Display`/`LowerHex` where appropriate or `DisplayHex` from `bitcoin_internals` which is faster.

  This change replaces the usages and removes the trait.

ACKs for top commit:
  tcharding:
    ACK 1b0988833a
  apoelstra:
    ACK 1b0988833a

Tree-SHA512: a1b508e24ac247a0692c01b7cb1e7fa8f23fbfa3d6c3d5dfe669eec01f940a96c3f88508cb0b2e3529eebd9cb51e7d41435dbd5f4cbaf3bc14b9c7e7d790308b
This commit is contained in:
Andrew Poelstra 2023-01-09 12:42:09 +00:00
commit 1f7affbc95
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
28 changed files with 171 additions and 281 deletions

View File

@ -885,7 +885,6 @@ mod tests {
use super::*;
use crate::crypto::key::PublicKey;
use crate::hashes::hex::ToHex;
use crate::internal_macros::{hex, hex_into, hex_script};
use crate::network::constants::Network::{Bitcoin, Testnet};
@ -1078,7 +1077,7 @@ mod tests {
];
for vector in &valid_vectors {
let addr: Address = vector.0.parse().unwrap();
assert_eq!(&addr.script_pubkey().as_bytes().to_hex(), vector.1);
assert_eq!(&addr.script_pubkey().to_hex_string(), vector.1);
roundtrips(&addr);
}

View File

@ -192,7 +192,6 @@ impl ChainHash {
#[cfg(test)]
mod test {
use super::*;
use crate::hashes::hex::ToHex;
use crate::network::constants::Network;
use crate::consensus::encode::serialize;
use crate::blockdata::locktime::absolute;
@ -216,7 +215,7 @@ mod test {
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
assert_eq!(gen.lock_time, absolute::LockTime::ZERO);
assert_eq!(gen.wtxid().to_hex(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
assert_eq!(gen.wtxid().to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
}
#[test]
@ -225,12 +224,12 @@ mod test {
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.merkle_root.to_hex(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
assert_eq!(gen.header.time, 1231006505);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
assert_eq!(gen.header.nonce, 2083236893);
assert_eq!(gen.header.block_hash().to_hex(), "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
assert_eq!(gen.header.block_hash().to_string(), "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
}
#[test]
@ -238,11 +237,11 @@ mod test {
let gen = genesis_block(Network::Testnet);
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.merkle_root.to_hex(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
assert_eq!(gen.header.time, 1296688602);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
assert_eq!(gen.header.nonce, 414098458);
assert_eq!(gen.header.block_hash().to_hex(), "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
assert_eq!(gen.header.block_hash().to_string(), "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
}
#[test]
@ -250,11 +249,11 @@ mod test {
let gen = genesis_block(Network::Signet);
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(gen.header.merkle_root.to_hex(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
assert_eq!(gen.header.time, 1598918400);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1e0377ae));
assert_eq!(gen.header.nonce, 52613770);
assert_eq!(gen.header.block_hash().to_hex(), "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6");
assert_eq!(gen.header.block_hash().to_string(), "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6");
}
// The *_chain_hash tests are sanity/regression tests, they verify that the const byte array
@ -304,7 +303,7 @@ mod test {
// Test vector taken from: https://github.com/lightning/bolts/blob/master/00-introduction.md
#[test]
fn mainnet_chain_hash_test_vector() {
let got = ChainHash::using_genesis_block(Network::Bitcoin).to_hex();
let got = ChainHash::using_genesis_block(Network::Bitcoin).to_string();
let want = "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000";
assert_eq!(got, want);
}

View File

@ -53,6 +53,7 @@ use crate::prelude::*;
use alloc::rc::Rc;
use alloc::sync::Arc;
use bitcoin_internals::debug_from_display;
use bitcoin_internals::hex::display::DisplayHex;
use crate::io;
use core::cmp::Ordering;
use core::convert::TryFrom;
@ -61,7 +62,6 @@ use core::{fmt, default::Default};
use core::ops::{Deref, DerefMut, Index, Range, RangeFull, RangeFrom, RangeTo, RangeInclusive, RangeToInclusive};
#[cfg(feature = "rust_v_1_53")]
use core::ops::Bound;
use bitcoin_hashes::hex::ToHex;
#[cfg(feature = "serde")] use serde;
@ -485,6 +485,15 @@ impl Script {
buf
}
/// Formats the script as lower-case hex.
///
/// This is a more convenient and performant way to write `format!("{:x}", script)`.
/// For better performance you should generally prefer displaying the script but if `String` is
/// required (this is common in tests) this method is can be used.
pub fn to_hex_string(&self) -> String {
self.as_bytes().to_lower_hex_string()
}
/// Returns the first opcode of the script (if there is any).
pub fn first_opcode(&self) -> Option<opcodes::All> {
self.as_bytes().first().copied().map(From::from)
@ -553,13 +562,6 @@ impl<'a> From<&'a Script> for Rc<Script> {
}
}
impl ToHex for Script {
#[inline]
fn to_hex(&self) -> String {
self.0.to_hex()
}
}
/// Iterator over bytes of a script
pub struct Bytes<'a>(core::iter::Copied<core::slice::Iter<'a, u8>>);
@ -662,19 +664,13 @@ impl fmt::Display for Script {
impl fmt::LowerHex for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for ch in self.bytes() {
write!(f, "{:02x}", ch)?;
}
Ok(())
fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
}
}
impl fmt::UpperHex for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for ch in self.bytes() {
write!(f, "{:02X}", ch)?;
}
Ok(())
fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
}
}
@ -1873,7 +1869,7 @@ impl serde::Serialize for Script {
S: serde::Serializer,
{
if serializer.is_human_readable() {
serializer.serialize_str(&self.to_hex())
serializer.collect_str(&format_args!("{:x}", self))
} else {
serializer.serialize_bytes(self.as_bytes())
}
@ -2011,7 +2007,7 @@ mod test {
use super::*;
use super::write_scriptint;
use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::hex::FromHex;
use crate::consensus::encode::{deserialize, serialize};
use crate::blockdata::opcodes;
use crate::crypto::key::PublicKey;
@ -2209,7 +2205,7 @@ mod test {
.push_opcode(OP_EQUALVERIFY)
.push_opcode(OP_CHECKSIG)
.into_script();
assert_eq!(script.to_hex(), "76a91416e1ae70ff0fa102905d4af297f6912bda6cce1988ac");
assert_eq!(script.to_hex_string(), "76a91416e1ae70ff0fa102905d4af297f6912bda6cce1988ac");
}
#[test]
@ -2241,7 +2237,7 @@ mod test {
let data = Vec::<u8>::from_hex("aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a").unwrap();
let op_return = ScriptBuf::new_op_return(&data);
assert!(op_return.is_op_return());
assert_eq!(op_return.to_hex(), "6a24aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a");
assert_eq!(op_return.to_hex_string(), "6a24aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a");
}
#[test]
@ -2249,71 +2245,71 @@ mod test {
let simple = Builder::new()
.push_verify()
.into_script();
assert_eq!(simple.to_hex(), "69");
assert_eq!(simple.to_hex_string(), "69");
let simple2 = Builder::from(vec![])
.push_verify()
.into_script();
assert_eq!(simple2.to_hex(), "69");
assert_eq!(simple2.to_hex_string(), "69");
let nonverify = Builder::new()
.push_verify()
.push_verify()
.into_script();
assert_eq!(nonverify.to_hex(), "6969");
assert_eq!(nonverify.to_hex_string(), "6969");
let nonverify2 = Builder::from(vec![0x69])
.push_verify()
.into_script();
assert_eq!(nonverify2.to_hex(), "6969");
assert_eq!(nonverify2.to_hex_string(), "6969");
let equal = Builder::new()
.push_opcode(OP_EQUAL)
.push_verify()
.into_script();
assert_eq!(equal.to_hex(), "88");
assert_eq!(equal.to_hex_string(), "88");
let equal2 = Builder::from(vec![0x87])
.push_verify()
.into_script();
assert_eq!(equal2.to_hex(), "88");
assert_eq!(equal2.to_hex_string(), "88");
let numequal = Builder::new()
.push_opcode(OP_NUMEQUAL)
.push_verify()
.into_script();
assert_eq!(numequal.to_hex(), "9d");
assert_eq!(numequal.to_hex_string(), "9d");
let numequal2 = Builder::from(vec![0x9c])
.push_verify()
.into_script();
assert_eq!(numequal2.to_hex(), "9d");
assert_eq!(numequal2.to_hex_string(), "9d");
let checksig = Builder::new()
.push_opcode(OP_CHECKSIG)
.push_verify()
.into_script();
assert_eq!(checksig.to_hex(), "ad");
assert_eq!(checksig.to_hex_string(), "ad");
let checksig2 = Builder::from(vec![0xac])
.push_verify()
.into_script();
assert_eq!(checksig2.to_hex(), "ad");
assert_eq!(checksig2.to_hex_string(), "ad");
let checkmultisig = Builder::new()
.push_opcode(OP_CHECKMULTISIG)
.push_verify()
.into_script();
assert_eq!(checkmultisig.to_hex(), "af");
assert_eq!(checkmultisig.to_hex_string(), "af");
let checkmultisig2 = Builder::from(vec![0xae])
.push_verify()
.into_script();
assert_eq!(checkmultisig2.to_hex(), "af");
assert_eq!(checkmultisig2.to_hex_string(), "af");
let trick_slice = Builder::new()
.push_slice(&[0xae]) // OP_CHECKMULTISIG
.push_verify()
.into_script();
assert_eq!(trick_slice.to_hex(), "01ae69");
assert_eq!(trick_slice.to_hex_string(), "01ae69");
let trick_slice2 = Builder::from(vec![0x01, 0xae])
.push_verify()
.into_script();
assert_eq!(trick_slice2.to_hex(), "01ae69");
assert_eq!(trick_slice2.to_hex_string(), "01ae69");
}
#[test]
@ -2361,10 +2357,10 @@ mod test {
#[test]
fn script_hashes() {
let script = hex_script!("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac");
assert_eq!(script.script_hash().to_hex(), "8292bcfbef1884f73c813dfe9c82fd7e814291ea");
assert_eq!(script.wscript_hash().to_hex(), "3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324");
assert_eq!(script.script_hash().to_string(), "8292bcfbef1884f73c813dfe9c82fd7e814291ea");
assert_eq!(script.wscript_hash().to_string(), "3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324");
assert_eq!(
hex_script!("20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac").tapscript_leaf_hash().to_hex(),
hex_script!("20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac").tapscript_leaf_hash().to_string(),
"5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21"
);
}

View File

@ -388,7 +388,6 @@ impl serde::Serialize for Witness {
where
S: serde::Serializer,
{
use crate::hashes::hex::ToHex;
use serde::ser::SerializeSeq;
let human_readable = serializer.is_human_readable();
@ -396,7 +395,7 @@ impl serde::Serialize for Witness {
for elem in self.iter() {
if human_readable {
seq.serialize_element(&elem.to_hex())?;
seq.serialize_element(&crate::serde_utils::SerializeBytesAsHex(elem))?;
} else {
seq.serialize_element(&elem)?;
}
@ -490,8 +489,8 @@ impl From<Vec<&[u8]>> for Witness {
mod test {
use super::*;
use bitcoin_internals::hex::display::DisplayHex;
use crate::consensus::{deserialize, serialize};
use crate::hashes::hex::ToHex;
use crate::internal_macros::hex;
use crate::Transaction;
use crate::secp256k1::ecdsa;
@ -654,15 +653,15 @@ mod test {
let expected_wit = ["304502210084622878c94f4c356ce49c8e33a063ec90f6ee9c0208540888cfab056cd1fca9022014e8dbfdfa46d318c6887afd92dcfa54510e057565e091d64d2ee3a66488f82c01", "026e181ffb98ebfe5a64c983073398ea4bcd1548e7b971b4c175346a25a1c12e95"];
for (i, wit_el) in tx.input[0].witness.iter().enumerate() {
assert_eq!(expected_wit[i], wit_el.to_hex());
assert_eq!(expected_wit[i], wit_el.to_lower_hex_string());
}
assert_eq!(expected_wit[1], tx.input[0].witness.last().unwrap().to_hex());
assert_eq!(expected_wit[0], tx.input[0].witness.second_to_last().unwrap().to_hex());
assert_eq!(expected_wit[0], tx.input[0].witness.nth(0).unwrap().to_hex());
assert_eq!(expected_wit[1], tx.input[0].witness.nth(1).unwrap().to_hex());
assert_eq!(expected_wit[1], tx.input[0].witness.last().unwrap().to_lower_hex_string());
assert_eq!(expected_wit[0], tx.input[0].witness.second_to_last().unwrap().to_lower_hex_string());
assert_eq!(expected_wit[0], tx.input[0].witness.nth(0).unwrap().to_lower_hex_string());
assert_eq!(expected_wit[1], tx.input[0].witness.nth(1).unwrap().to_lower_hex_string());
assert_eq!(None, tx.input[0].witness.nth(2));
assert_eq!(expected_wit[0], tx.input[0].witness[0].to_hex());
assert_eq!(expected_wit[1], tx.input[0].witness[1].to_hex());
assert_eq!(expected_wit[0], tx.input[0].witness[0].to_lower_hex_string());
assert_eq!(expected_wit[1], tx.input[0].witness[1].to_lower_hex_string());
let tx_bytes_back = serialize(&tx);
assert_eq!(tx_bytes_back, tx_bytes);

View File

@ -21,6 +21,7 @@ use crate::prelude::*;
use core::{fmt, mem, u32, convert::From};
use bitcoin_internals::write_err;
use bitcoin_internals::hex::display::DisplayHex;
use crate::hashes::{sha256d, Hash, sha256};
use crate::hash_types::{BlockHash, FilterHash, TxMerkleNode, FilterHeader};
@ -29,7 +30,6 @@ use crate::io::{self, Cursor, Read};
use crate::psbt;
use crate::bip152::{ShortId, PrefilledTransaction};
use crate::taproot::TapLeafHash;
use crate::hashes::hex::ToHex;
use crate::blockdata::transaction::{TxOut, Transaction, TxIn};
#[cfg(feature = "std")]
@ -73,7 +73,7 @@ impl fmt::Display for Error {
Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f,
"allocation of oversized vector: requested {}, maximum {}", r, m),
Error::InvalidChecksum { expected: ref e, actual: ref a } => write!(f,
"invalid checksum: expected {}, actual {}", e.to_hex(), a.to_hex()),
"invalid checksum: expected {:x}, actual {:x}", e.as_hex(), a.as_hex()),
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
Error::ParseFailed(ref s) => write!(f, "parse failed: {}", s),
Error::UnsupportedSegwitFlag(ref swflag) => write!(f,
@ -124,7 +124,7 @@ pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> {
/// Encodes an object into a hex-encoded string.
pub fn serialize_hex<T: Encodable + ?Sized>(data: &T) -> String {
serialize(data)[..].to_hex()
serialize(data).to_lower_hex_string()
}
/// Deserializes an object from a vector, will error if said deserialization

View File

@ -9,6 +9,7 @@ use core::str::FromStr;
use core::{fmt, iter};
use bitcoin_internals::write_err;
use bitcoin_internals::hex::display::DisplayHex;
use secp256k1;
use crate::prelude::*;
@ -58,8 +59,8 @@ impl Signature {
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
hex::format_hex(&self.sig.serialize_der(), f)?;
hex::format_hex(&[self.hash_ty as u8], f)
fmt::LowerHex::fmt(&self.sig.serialize_der().as_hex(), f)?;
fmt::LowerHex::fmt(&[self.hash_ty as u8].as_hex(), f)
}
}

View File

@ -548,7 +548,7 @@ mod tests {
use super::{PrivateKey, PublicKey, SortKey};
use secp256k1::Secp256k1;
use std::str::FromStr;
use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::hex::FromHex;
use crate::network::constants::Network::Testnet;
use crate::network::constants::Network::Bitcoin;
use crate::address::Address;
@ -593,15 +593,15 @@ mod tests {
fn test_pubkey_hash() {
let pk = PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap();
let upk = PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap();
assert_eq!(pk.pubkey_hash().to_hex(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4");
assert_eq!(upk.pubkey_hash().to_hex(), "ac2e7daf42d2c97418fd9f78af2de552bb9c6a7a");
assert_eq!(pk.pubkey_hash().to_string(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4");
assert_eq!(upk.pubkey_hash().to_string(), "ac2e7daf42d2c97418fd9f78af2de552bb9c6a7a");
}
#[test]
fn test_wpubkey_hash() {
let pk = PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap();
let upk = PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap();
assert_eq!(pk.wpubkey_hash().unwrap().to_hex(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4");
assert_eq!(pk.wpubkey_hash().unwrap().to_string(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4");
assert_eq!(upk.wpubkey_hash(), None);
}

View File

@ -109,7 +109,8 @@ mod test_macros {
/// Implements several traits for byte-based newtypes.
/// Implements:
/// - core::fmt::LowerHex (implies hashes::hex::ToHex)
/// - core::fmt::LowerHex
/// - core::fmt::UpperHex
/// - core::fmt::Display
/// - core::str::FromStr
/// - hashes::hex::FromHex
@ -134,10 +135,15 @@ macro_rules! impl_bytes_newtype {
impl core::fmt::LowerHex for $t {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
for &ch in self.0.iter() {
write!(f, "{:02x}", ch)?;
}
Ok(())
use bitcoin_internals::hex::{Case, display};
display::fmt_hex_exact!(f, $len, &self.0, Case::Lower)
}
}
impl core::fmt::UpperHex for $t {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
use bitcoin_internals::hex::{Case, display};
display::fmt_hex_exact!(f, $len, &self.0, Case::Upper)
}
}
@ -184,7 +190,7 @@ macro_rules! impl_bytes_newtype {
impl $crate::serde::Serialize for $t {
fn serialize<S: $crate::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
s.serialize_str(&$crate::hashes::hex::ToHex::to_hex(self))
s.collect_str(self)
} else {
s.serialize_bytes(&self[..])
}

View File

@ -499,6 +499,7 @@ impl Decodable for MerkleBlock {
#[cfg(test)]
mod tests {
use bitcoin_internals::hex::display::DisplayHex;
#[cfg(feature = "rand-std")]
use secp256k1::rand::prelude::*;
@ -506,7 +507,7 @@ mod tests {
use crate::consensus::encode::{deserialize, serialize};
#[cfg(feature = "rand-std")]
use crate::hash_types::TxMerkleNode;
use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::hex::FromHex;
#[cfg(feature = "rand-std")]
use crate::hashes::Hash;
use crate::internal_macros::hex;
@ -656,7 +657,7 @@ mod tests {
mb.txn.extract_matches(&mut vec![], &mut vec![]).unwrap()
);
// Serialize again and check that it matches the original bytes
assert_eq!(MB_HEX, serialize(&mb).to_hex().as_str());
assert_eq!(MB_HEX, serialize(&mb).to_lower_hex_string().as_str());
}
/// Create a CMerkleBlock using a list of txids which will be found in the

View File

@ -774,21 +774,16 @@ impl fmt::Debug for U256 {
}
macro_rules! impl_hex {
($hex:ident, $fmt:literal) => {
($hex:ident, $case:expr) => {
impl $hex for U256 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if f.alternate() {
write!(f, "0x")?;
}
write!(f, $fmt, self.0)?;
write!(f, $fmt, self.1)?;
Ok(())
bitcoin_internals::hex::display::fmt_hex_exact!(f, 32, &self.to_be_bytes(), $case)
}
}
};
}
impl_hex!(LowerHex, "{:032x}");
impl_hex!(UpperHex, "{:032X}");
impl_hex!(LowerHex, bitcoin_internals::hex::Case::Lower);
impl_hex!(UpperHex, bitcoin_internals::hex::Case::Upper);
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
@ -797,12 +792,17 @@ impl crate::serde::Serialize for U256 {
where
S: crate::serde::Serializer,
{
use crate::hashes::hex::ToHex;
let bytes = self.to_be_bytes();
struct DisplayHex(U256);
impl fmt::Display for DisplayHex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:x}", self.0) }
}
if serializer.is_human_readable() {
// TODO: fast hex encoding.
serializer.serialize_str(&bytes.to_hex())
serializer.collect_str(&DisplayHex(*self))
} else {
let bytes = self.to_be_bytes();
serializer.serialize_bytes(&bytes)
}
}

View File

@ -6,13 +6,13 @@
//! <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki>.
//!
use bitcoin_internals::hex::display::DisplayHex;
use crate::prelude::*;
use core::fmt;
use core::convert::TryFrom;
use crate::io::{self, Cursor};
use crate::consensus::encode::{self, ReadExt, WriteExt, Decodable, Encodable, VarInt, serialize, deserialize, MAX_VEC_SIZE};
use crate::hashes::hex;
use crate::psbt::Error;
use super::serialize::{Serialize, Deserialize};
@ -66,8 +66,7 @@ pub struct ProprietaryKey<Subtype=ProprietaryType> where Subtype: Copy + From<u8
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "type: {:#x}, key: ", self.type_value)?;
hex::format_hex(&self.key[..], f)
write!(f, "type: {:#x}, key: {:x}", self.type_value, self.key.as_hex())
}
}

View File

@ -44,7 +44,8 @@ pub(crate) trait Deserialize: Sized {
impl PartiallySignedTransaction {
/// Serialize a value as bytes in hex.
pub fn serialize_hex(&self) -> String {
bitcoin_hashes::hex::ToHex::to_hex(&self.serialize()[..])
use bitcoin_internals::hex::display::DisplayHex;
self.serialize().to_lower_hex_string()
}
/// Serialize as raw binary data

View File

@ -5,6 +5,20 @@
//! This module is for special serde serializations.
//!
pub(crate) struct SerializeBytesAsHex<'a>(pub(crate) &'a [u8]);
impl<'a> serde::Serialize for SerializeBytesAsHex<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use bitcoin_internals::hex::display::DisplayHex;
serializer.collect_str(&format_args!("{:x}", self.0.as_hex()))
}
}
pub mod btreemap_byte_values {
//! Module for serialization of BTreeMaps with hex byte values.
#![allow(missing_docs)]
@ -13,7 +27,7 @@ pub mod btreemap_byte_values {
use serde;
use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::hex::FromHex;
use crate::prelude::*;
pub fn serialize<S, T>(v: &BTreeMap<T, Vec<u8>>, s: S) -> Result<S::Ok, S::Error>
@ -29,7 +43,7 @@ pub mod btreemap_byte_values {
} else {
let mut map = s.serialize_map(Some(v.len()))?;
for (key, value) in v.iter() {
map.serialize_entry(key, &value.to_hex())?;
map.serialize_entry(key, &super::SerializeBytesAsHex(value))?;
}
map.end()
}
@ -237,7 +251,7 @@ pub mod hex_bytes {
use serde;
use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::hex::FromHex;
pub fn serialize<T, S>(bytes: &T, s: S) -> Result<S::Ok, S::Error>
where
@ -248,7 +262,7 @@ pub mod hex_bytes {
if !s.is_human_readable() {
serde::Serialize::serialize(bytes, s)
} else {
s.serialize_str(&bytes.as_ref().to_hex())
serde::Serialize::serialize(&super::SerializeBytesAsHex(bytes.as_ref()), s)
}
}

View File

@ -1387,10 +1387,10 @@ mod tests {
})
}
use bitcoin_internals::hex::display::DisplayHex;
use secp256k1::{self, SecretKey, XOnlyPublicKey};
use crate::consensus::serde as con_serde;
use crate::hashes::hex::ToHex;
use crate::taproot::{TapBranchHash, TapTweakHash};
#[derive(serde::Deserialize)]
@ -1551,7 +1551,7 @@ mod tests {
assert_eq!(expected.internal_pubkey, internal_key);
assert_eq!(expected.tweak, tweak);
assert_eq!(expected.sig_msg, sig_msg.to_hex());
assert_eq!(expected.sig_msg, sig_msg.to_lower_hex_string());
assert_eq!(expected.sig_hash, sighash);
assert_eq!(expected_hash_ty, hash_ty);
assert_eq!(expected_key_spend_sig, key_spend_sig);

View File

@ -213,13 +213,12 @@ pub fn signed_msg_hash(msg: &str) -> sha256d::Hash {
#[cfg(test)]
mod tests {
use super::*;
use crate::hashes::hex::ToHex;
#[test]
fn test_signed_msg_hash() {
let hash = signed_msg_hash("test");
assert_eq!(
hash.to_hex(),
hash.to_string(),
"a6f87fe6d58a032c320ff8d1541656f0282c2c7bfcc69d61af4c8e8ed528e49c"
);
}

View File

@ -1094,11 +1094,12 @@ impl std::error::Error for TaprootError {
mod test {
use core::str::FromStr;
use bitcoin_internals::hex::display::DisplayHex;
use secp256k1::{VerifyOnly, XOnlyPublicKey};
use super::*;
use crate::crypto::schnorr::TapTweak;
use crate::hashes::hex::{FromHex, ToHex};
use crate::hashes::hex::FromHex;
use crate::hashes::sha256t::Tag;
use crate::hashes::{sha256, Hash, HashEngine};
use crate::{Address, Network};
@ -1149,19 +1150,19 @@ mod test {
// CHashWriter writer = HasherTapLeaf;
// writer.GetSHA256().GetHex()
assert_eq!(
TapLeafHash::from_engine(TapLeafTag::engine()).to_hex(),
TapLeafHash::from_engine(TapLeafTag::engine()).to_string(),
"5212c288a377d1f8164962a5a13429f9ba6a7b84e59776a52c6637df2106facb"
);
assert_eq!(
TapBranchHash::from_engine(TapBranchTag::engine()).to_hex(),
TapBranchHash::from_engine(TapBranchTag::engine()).to_string(),
"53c373ec4d6f3c53c1f5fb2ff506dcefe1a0ed74874f93fa93c8214cbe9ffddf"
);
assert_eq!(
TapTweakHash::from_engine(TapTweakTag::engine()).to_hex(),
TapTweakHash::from_engine(TapTweakTag::engine()).to_string(),
"8aa4229474ab0100b2d6f0687f031d1fc9d8eef92a042ad97d279bff456b15e4"
);
assert_eq!(
TapSighashHash::from_engine(TapSighashTag::engine()).to_hex(),
TapSighashHash::from_engine(TapSighashTag::engine()).to_string(),
"dabc11914abcd8072900042a2681e52f8dba99ce82e224f97b5fdb7cd4b9c803"
);
@ -1171,19 +1172,19 @@ mod test {
// writer.GetSHA256().GetHex()
// Note that Core writes the 0 length prefix when an empty vector is written.
assert_eq!(
TapLeafHash::hash(&[0]).to_hex(),
TapLeafHash::hash(&[0]).to_string(),
"ed1382037800c9dd938dd8854f1a8863bcdeb6705069b4b56a66ec22519d5829"
);
assert_eq!(
TapBranchHash::hash(&[0]).to_hex(),
TapBranchHash::hash(&[0]).to_string(),
"92534b1960c7e6245af7d5fda2588db04aa6d646abc2b588dab2b69e5645eb1d"
);
assert_eq!(
TapTweakHash::hash(&[0]).to_hex(),
TapTweakHash::hash(&[0]).to_string(),
"cd8737b5e6047fc3f16f03e8b9959e3440e1bdf6dd02f7bb899c352ad490ea1e"
);
assert_eq!(
TapSighashHash::hash(&[0]).to_hex(),
TapSighashHash::hash(&[0]).to_string(),
"c2fd0de003889a09c4afcf676656a0d8a1fb706313ff7d509afb00c323c010cd"
);
}
@ -1199,7 +1200,7 @@ mod test {
let script = ScriptBuf::from_hex(script_hex).unwrap();
let control_block =
ControlBlock::from_slice(&Vec::<u8>::from_hex(control_block_hex).unwrap()).unwrap();
assert_eq!(control_block_hex, control_block.serialize().to_hex());
assert_eq!(control_block_hex, control_block.serialize().to_lower_hex_string());
assert!(control_block.verify_taproot_commitment(secp, out_pk.to_inner(), &script));
}
@ -1429,7 +1430,7 @@ mod test {
let leaf_hash = TapLeafHash::from_script(&script_ver.0, script_ver.1);
let ctrl_blk = spend_info.control_block(script_ver).unwrap();
assert_eq!(leaf_hash.to_hex(), expected_leaf_hash);
assert_eq!(leaf_hash.to_string(), expected_leaf_hash);
assert_eq!(ctrl_blk, expected_ctrl_blk);
}
}

View File

@ -13,12 +13,12 @@ edition = "2018"
[features]
default = ["std"]
std = []
std = ["internals/alloc"]
schemars = ["actual-schemars", "dyn-clone"]
# If you disable std, you can still use a Write trait via the core2 feature.
# You can also use ToHex via the alloc feature, as it requires Vec/String.
# And you can still just disable std by disabling default features, without enabling these two.
alloc = ["core2/alloc"]
alloc = ["core2/alloc", "internals/alloc"]
serde-std = ["serde/std"]
[dependencies]

View File

@ -9,7 +9,7 @@ extern crate bitcoin_hashes;
#[cfg(feature = "alloc")] use alloc_cortex_m::CortexMHeap;
#[cfg(feature = "alloc")] use core::alloc::Layout;
#[cfg(feature = "alloc")] use cortex_m::asm;
#[cfg(feature = "alloc")] use bitcoin_hashes::hex::ToHex;
#[cfg(feature = "alloc")] use alloc::string::ToString;
use bitcoin_hashes::{sha256, Hash, HashEngine};
use core2::io::Write;
@ -57,7 +57,7 @@ fn check_result(engine: sha256::HashEngine) {
}
#[cfg(feature = "alloc")]
if hash.to_hex() != hash_check.to_hex() {
if hash.to_string() != hash_check.to_string() {
debug::exit(debug::EXIT_FAILURE);
}
}

View File

@ -52,7 +52,7 @@ mod tests {
#[cfg(any(feature = "std", feature = "alloc"))]
fn test() {
use crate::{hash160, Hash, HashEngine};
use crate::hex::{FromHex, ToHex};
use crate::hex::FromHex;
#[derive(Clone)]
#[cfg(any(feature = "std", feature = "alloc"))]
@ -89,7 +89,7 @@ mod tests {
let hash = hash160::Hash::hash(&test.input[..]);
assert_eq!(hash, hash160::Hash::from_hex(test.output_str).expect("parse hex"));
assert_eq!(&hash[..], &test.output[..]);
assert_eq!(&hash.to_hex(), &test.output_str);
assert_eq!(&hash.to_string(), &test.output_str);
// Hash through engine, checking that we can input byte by byte
let mut engine = hash160::Hash::engine();

View File

@ -17,8 +17,6 @@
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::alloc::{string::String, vec::Vec};
#[cfg(feature = "alloc")]
use crate::alloc::format;
#[cfg(any(test, feature = "std"))]
use std::io;
@ -49,14 +47,6 @@ impl fmt::Display for Error {
}
}
/// Trait for objects that can be serialized as hex strings.
#[cfg(any(test, feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(test, feature = "std", feature = "alloc"))))]
pub trait ToHex {
/// Converts to a hexadecimal representation of the object.
fn to_hex(&self) -> String;
}
/// Trait for objects that can be deserialized from hex strings.
pub trait FromHex: Sized {
/// Produces an object from a byte iterator.
@ -70,15 +60,6 @@ pub trait FromHex: Sized {
}
}
#[cfg(any(test, feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(test, feature = "std", feature = "alloc"))))]
impl<T: fmt::LowerHex> ToHex for T {
/// Outputs the hash in hexadecimal form.
fn to_hex(&self) -> String {
format!("{:x}", self)
}
}
impl<T: Hash> FromHex for T {
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
where
@ -170,65 +151,8 @@ impl<'a> DoubleEndedIterator for HexIterator<'a> {
impl<'a> ExactSizeIterator for HexIterator<'a> {}
/// Outputs hex into an object implementing `fmt::Write`.
///
/// This is usually more efficient than going through a `String` using [`ToHex`].
pub fn format_hex(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
let prec = f.precision().unwrap_or(2 * data.len());
let width = f.width().unwrap_or(2 * data.len());
for _ in (2 * data.len())..width {
f.write_str("0")?;
}
for ch in data.iter().take(prec / 2) {
write!(f, "{:02x}", *ch)?;
}
if prec < 2 * data.len() && prec % 2 == 1 {
write!(f, "{:x}", data[prec / 2] / 16)?;
}
Ok(())
}
/// Outputs hex in reverse order.
///
/// Used for `sha256d::Hash` whose standard hex encoding has the bytes reversed.
pub fn format_hex_reverse(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
let prec = f.precision().unwrap_or(2 * data.len());
let width = f.width().unwrap_or(2 * data.len());
for _ in (2 * data.len())..width {
f.write_str("0")?;
}
for ch in data.iter().rev().take(prec / 2) {
write!(f, "{:02x}", *ch)?;
}
if prec < 2 * data.len() && prec % 2 == 1 {
write!(f, "{:x}", data[data.len() - 1 - prec / 2] / 16)?;
}
Ok(())
}
#[cfg(any(test, feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(test, feature = "std", feature = "alloc"))))]
impl ToHex for [u8] {
fn to_hex(&self) -> String {
use core::fmt::Write;
let mut ret = String::with_capacity(2 * self.len());
for ch in self {
write!(ret, "{:02x}", ch).expect("writing to string");
}
ret
}
}
/// A struct implementing [`io::Write`] that converts what's written to it into
/// a hex String.
///
/// If you already have the data to be converted in a `Vec<u8>` use [`ToHex`]
/// but if you have an encodable object, by using this you avoid the
/// serialization to `Vec<u8>` by going directly to `String`.
///
/// Note that to achieve better perfomance than [`ToHex`] the struct must be
/// created with the right `capacity` of the final hex string so that the inner
/// `String` doesn't re-allocate.
#[cfg(any(test, feature = "std", feature = "alloc"))]
#[cfg_attr(docsrs, doc(cfg(any(test, feature = "std", feature = "alloc"))))]
pub struct HexWriter(String);
@ -319,8 +243,9 @@ impl_fromhex_array!(512);
#[cfg(test)]
mod tests {
use super::*;
#[cfg(any(feature = "std", feature = "alloc"))]
use internals::hex::exts::DisplayHex;
use core::fmt;
use std::io::Write;
#[test]
@ -331,86 +256,20 @@ mod tests {
let parse: Vec<u8> = FromHex::from_hex(expected).expect("parse lowercase string");
assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
let ser = parse.to_hex();
let ser = parse.to_lower_hex_string();
assert_eq!(ser, expected);
let parse: Vec<u8> = FromHex::from_hex(expected_up).expect("parse uppercase string");
assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
let ser = parse.to_hex();
let ser = parse.to_lower_hex_string();
assert_eq!(ser, expected);
let parse: [u8; 8] = FromHex::from_hex(expected_up).expect("parse uppercase string");
assert_eq!(parse, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
let ser = parse.to_hex();
let ser = parse.to_lower_hex_string();
assert_eq!(ser, expected);
}
#[test]
fn hex_truncate() {
struct HexBytes(Vec<u8>);
impl fmt::LowerHex for HexBytes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format_hex(&self.0, f)
}
}
let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(
format!("{:x}", bytes),
"0102030405060708090a"
);
for i in 0..20 {
assert_eq!(
format!("{:.prec$x}", bytes, prec = i),
&"0102030405060708090a"[0..i]
);
}
assert_eq!(
format!("{:25x}", bytes),
"000000102030405060708090a"
);
assert_eq!(
format!("{:26x}", bytes),
"0000000102030405060708090a"
);
}
#[test]
fn hex_truncate_rev() {
struct HexBytes(Vec<u8>);
impl fmt::LowerHex for HexBytes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format_hex_reverse(&self.0, f)
}
}
let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(
format!("{:x}", bytes),
"0a090807060504030201"
);
for i in 0..20 {
assert_eq!(
format!("{:.prec$x}", bytes, prec = i),
&"0a090807060504030201"[0..i]
);
}
assert_eq!(
format!("{:25x}", bytes),
"000000a090807060504030201"
);
assert_eq!(
format!("{:26x}", bytes),
"0000000a090807060504030201"
);
}
#[test]
#[cfg(any(feature = "std", feature = "alloc"))]
fn hex_error() {
@ -447,18 +306,19 @@ mod tests {
#[test]
#[cfg(any(feature = "std", feature = "alloc"))]
fn hex_writer() {
let vec: Vec<_> = (0u8..32).collect();
let mut writer = HexWriter::new(64);
writer.write_all(&vec[..]).unwrap();
assert_eq!(vec.to_hex(), writer.result());
assert_eq!(vec.to_lower_hex_string(), writer.result());
}
}
#[cfg(bench)]
mod benches {
use test::{Bencher, black_box};
use super::{ToHex, HexWriter};
use super::HexWriter;
use std::io::Write;
use crate::{sha256, Hash};
@ -466,7 +326,7 @@ mod benches {
fn bench_to_hex(bh: &mut Bencher) {
let hash = sha256::Hash::hash(&[0; 1]);
bh.iter(|| {
black_box(hash.to_hex());
black_box(hash.to_string());
})
}

View File

@ -408,7 +408,7 @@ mod tests {
#[cfg(any(feature = "std", feature = "alloc"))]
fn test() {
use crate::{Hash, HashEngine, ripemd160};
use crate::hex::{FromHex, ToHex};
use crate::hex::FromHex;
#[derive(Clone)]
struct Test {
@ -472,7 +472,7 @@ mod tests {
let hash = ripemd160::Hash::hash(test.input.as_bytes());
assert_eq!(hash, ripemd160::Hash::from_hex(test.output_str).expect("parse hex"));
assert_eq!(&hash[..], &test.output[..]);
assert_eq!(&hash.to_hex(), &test.output_str);
assert_eq!(&hash.to_string(), &test.output_str);
// Hash through engine, checking that we can input byte by byte
let mut engine = ripemd160::Hash::engine();

View File

@ -146,7 +146,7 @@ mod tests {
#[cfg(any(feature = "std", feature = "alloc"))]
fn test() {
use crate::{sha1, Hash, HashEngine};
use crate::hex::{FromHex, ToHex};
use crate::hex::FromHex;
#[derive(Clone)]
struct Test {
@ -198,7 +198,7 @@ mod tests {
let hash = sha1::Hash::hash(test.input.as_bytes());
assert_eq!(hash, sha1::Hash::from_hex(test.output_str).expect("parse hex"));
assert_eq!(&hash[..], &test.output[..]);
assert_eq!(&hash.to_hex(), &test.output_str);
assert_eq!(&hash.to_string(), &test.output_str);
// Hash through engine, checking that we can input byte by byte
let mut engine = sha1::Hash::engine();

View File

@ -326,7 +326,7 @@ mod tests {
#[test]
#[cfg(any(feature = "std", feature = "alloc"))]
fn test() {
use crate::hex::{FromHex, ToHex};
use crate::hex::FromHex;
#[derive(Clone)]
struct Test {
@ -374,7 +374,7 @@ mod tests {
let hash = sha256::Hash::hash(test.input.as_bytes());
assert_eq!(hash, sha256::Hash::from_hex(test.output_str).expect("parse hex"));
assert_eq!(&hash[..], &test.output[..]);
assert_eq!(&hash.to_hex(), &test.output_str);
assert_eq!(&hash.to_string(), &test.output_str);
// Hash through engine, checking that we can input byte by byte
let mut engine = sha256::Hash::engine();

View File

@ -49,7 +49,7 @@ mod tests {
#[cfg(any(feature = "std", feature = "alloc"))]
fn test() {
use crate::{sha256d, Hash, HashEngine};
use crate::hex::{FromHex, ToHex};
use crate::hex::FromHex;
#[derive(Clone)]
struct Test {
@ -77,7 +77,7 @@ mod tests {
let hash = sha256d::Hash::hash(test.input.as_bytes());
assert_eq!(hash, sha256d::Hash::from_hex(test.output_str).expect("parse hex"));
assert_eq!(&hash[..], &test.output[..]);
assert_eq!(&hash.to_hex(), &test.output_str);
assert_eq!(&hash.to_string(), &test.output_str);
// Hash through engine, checking that we can input byte by byte
let mut engine = sha256d::Hash::engine();

View File

@ -123,8 +123,6 @@ macro_rules! sha256t_hash_newtype {
mod tests {
use crate::{sha256, sha256t};
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::hex::ToHex;
#[cfg(any(feature = "std", feature = "alloc"))]
use crate::Hash;
const TEST_MIDSTATE: [u8; 32] = [
@ -154,11 +152,11 @@ mod tests {
#[cfg(any(feature = "std", feature = "alloc"))]
fn test_sha256t() {
assert_eq!(
TestHash::hash(&[0]).to_hex(),
TestHash::hash(&[0]).to_string(),
"29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed"
);
assert_eq!(
NewTypeHash::hash(&[0]).to_hex(),
NewTypeHash::hash(&[0]).to_string(),
"29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed"
);
}

View File

@ -311,7 +311,7 @@ mod tests {
#[cfg(any(feature = "std", feature = "alloc"))]
fn test() {
use crate::{sha512, Hash, HashEngine};
use crate::hex::{FromHex, ToHex};
use crate::hex::FromHex;
#[derive(Clone)]
struct Test {
@ -371,7 +371,7 @@ mod tests {
let hash = sha512::Hash::hash(test.input.as_bytes());
assert_eq!(hash, sha512::Hash::from_hex(test.output_str).expect("parse hex"));
assert_eq!(&hash[..], &test.output[..]);
assert_eq!(&hash.to_hex(), &test.output_str);
assert_eq!(&hash.to_string(), &test.output_str);
// Hash through engine, checking that we can input byte by byte
let mut engine = sha512::Hash::engine();

View File

@ -89,7 +89,7 @@ mod tests {
#[cfg(any(feature = "std", feature = "alloc"))]
fn test() {
use crate::{sha512_256, Hash, HashEngine};
use crate::hex::{FromHex, ToHex};
use crate::hex::FromHex;
#[derive(Clone)]
struct Test {
@ -157,7 +157,7 @@ mod tests {
let hash = sha512_256::Hash::hash(test.input.as_bytes());
assert_eq!(hash, sha512_256::Hash::from_hex(test.output_str).expect("parse hex"));
assert_eq!(&hash[..], &test.output[..]);
assert_eq!(&hash.to_hex(), &test.output_str);
assert_eq!(&hash.to_string(), &test.output_str);
// Hash through engine, checking that we can input byte by byte
let mut engine = sha512_256::Hash::engine();

View File

@ -111,6 +111,23 @@ impl<'a> DisplayHex for &'a [u8] {
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(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>::display_hex`](DisplayHex::display_hex).