use std::{
cmp::Ordering,
fmt::{self, Display},
str::FromStr,
};
use bitcoin::hashes::Hash as _;
use serde::{Deserialize, Serialize};
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Txid(pub bitcoin::Txid);
impl Display for Txid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
bitcoin::Txid::fmt(&self.0, f)
}
}
impl FromStr for Txid {
type Err = bitcoin::hex::HexToArrayError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
bitcoin::Txid::from_str(s).map(Self)
}
}
impl Ord for Txid {
fn cmp(&self, other: &Self) -> Ordering {
self.0
.as_raw_hash()
.as_byte_array()
.iter()
.rev()
.cmp(other.0.as_byte_array().iter().rev())
}
}
impl PartialOrd for Txid {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[cfg(any(test, feature = "test-utils"))]
mod arbitrary_impl {
use proptest::{
arbitrary::{Arbitrary, any},
strategy::{BoxedStrategy, Strategy},
};
use super::*;
impl Arbitrary for Txid {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
any::<[u8; 32]>()
.prop_map(bitcoin::Txid::from_byte_array)
.prop_map(Self)
.boxed()
}
}
}
#[cfg(test)]
mod test {
use proptest::{arbitrary::any, prop_assert_eq, proptest};
use super::*;
use crate::test_utils::roundtrip;
#[test]
fn txid_roundtrip() {
roundtrip::fromstr_display_roundtrip_proptest::<Txid>();
roundtrip::json_string_roundtrip_proptest::<Txid>();
roundtrip::bcs_roundtrip_proptest::<Txid>();
}
#[test]
fn txid_ordering_equivalence() {
proptest!(|(txid1 in any::<Txid>(), txid2 in any::<Txid>())| {
let txid1_str = txid1.to_string();
let txid2_str = txid2.to_string();
let unserialized_order = txid1.cmp(&txid2);
let string_serialized_order = txid1_str.cmp(&txid2_str);
prop_assert_eq!(unserialized_order, string_serialized_order);
});
}
}