use alloc::string::{String, ToString};
use core::fmt;
use corez::io::{self, Read, Write};
use zcash_encoding::ReverseHex;
#[cfg(feature = "std")]
use memuse::DynamicUsage;
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct TxId([u8; 32]);
#[cfg(feature = "std")]
memuse::impl_no_dynamic_usage!(TxId);
impl fmt::Debug for TxId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let txid_str = self.to_string();
f.debug_tuple("TxId").field(&txid_str).finish()
}
}
impl fmt::Display for TxId {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(&self.as_hex())
}
}
impl AsRef<[u8; 32]> for TxId {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
impl From<TxId> for [u8; 32] {
fn from(value: TxId) -> Self {
value.0
}
}
impl TxId {
pub const NULL: TxId = TxId([0u8; 32]);
pub const fn from_bytes(bytes: [u8; 32]) -> Self {
TxId(bytes)
}
pub fn as_hex(&self) -> String {
ReverseHex::encode(&self.0)
}
pub fn from_hex(s: &str) -> Option<Self> {
ReverseHex::decode(s).map(TxId::from_bytes)
}
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let mut hash = [0u8; 32];
reader.read_exact(&mut hash)?;
Ok(TxId::from_bytes(hash))
}
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(&self.0)?;
Ok(())
}
pub fn is_null(&self) -> bool {
*self == Self::NULL
}
}
#[cfg(any(test, feature = "test-dependencies"))]
pub mod testing {
use super::TxId;
use proptest::prelude::*;
pub fn arb_txid() -> impl Strategy<Value = TxId> {
any::<[u8; 32]>().prop_map(TxId::from_bytes)
}
}
#[cfg(test)]
mod tests {
use super::TxId;
use alloc::string::ToString;
#[test]
fn from_hex_inverts_display() {
let bytes: [u8; 32] = core::array::from_fn(|i| i as u8);
let txid = TxId::from_bytes(bytes);
assert_eq!(TxId::from_hex(&txid.to_string()), Some(txid));
assert_eq!(
TxId::from_hex(&hex::encode(bytes)),
Some(TxId::from_bytes({
let mut r = bytes;
r.reverse();
r
})),
"internal-order hex parses as the REVERSED id"
);
assert_eq!(TxId::from_hex("beef"), None);
assert_eq!(TxId::from_hex("zz"), None);
}
}