use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
use bitcoin::hex::HexToArrayError;
use bitcoin::{OutPoint as Outpoint, Txid};
use crate::seals::txout::seal::{SealTxid, TxPtr};
use crate::seals::txout::{TxoSeal, WitnessVoutError};
use crate::{dbc, Vout};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = dbc::LIB_NAME_BPCORE)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]
pub struct ExplicitSeal<Id: SealTxid> {
pub txid: Id,
pub vout: Vout,
}
impl TryFrom<&ExplicitSeal<TxPtr>> for Outpoint {
type Error = WitnessVoutError;
#[inline]
fn try_from(reveal: &ExplicitSeal<TxPtr>) -> Result<Self, Self::Error> {
reveal
.txid
.map_to_outpoint(reveal.vout)
.ok_or(WitnessVoutError)
}
}
impl TryFrom<ExplicitSeal<TxPtr>> for Outpoint {
type Error = WitnessVoutError;
#[inline]
fn try_from(reveal: ExplicitSeal<TxPtr>) -> Result<Self, Self::Error> {
Outpoint::try_from(&reveal)
}
}
impl From<&ExplicitSeal<Txid>> for Outpoint {
fn from(seal: &ExplicitSeal<Txid>) -> Self { Outpoint::new(seal.txid, seal.vout.into_u32()) }
}
impl From<ExplicitSeal<Txid>> for Outpoint {
fn from(seal: ExplicitSeal<Txid>) -> Self { Outpoint::from(&seal) }
}
impl<Id: SealTxid> TxoSeal for ExplicitSeal<Id> {
#[inline]
fn txid(&self) -> Option<Txid> { self.txid.txid() }
#[inline]
fn vout(&self) -> Vout { self.vout }
#[inline]
fn outpoint(&self) -> Option<Outpoint> { self.txid.map_to_outpoint(self.vout) }
#[inline]
fn txid_or(&self, default_txid: Txid) -> Txid { self.txid.txid_or(default_txid) }
#[inline]
fn outpoint_or(&self, default_txid: Txid) -> Outpoint {
Outpoint::new(self.txid.txid_or(default_txid), self.vout.into_u32())
}
}
impl<Id: SealTxid> ExplicitSeal<Id> {
#[inline]
pub fn new(outpoint: Outpoint) -> ExplicitSeal<Id> {
Self {
txid: Id::from(outpoint.txid),
vout: Vout::from_u32(outpoint.vout),
}
}
#[inline]
pub fn with(txid: Id, vout: impl Into<Vout>) -> ExplicitSeal<Id> {
ExplicitSeal {
txid,
vout: vout.into(),
}
}
}
impl ExplicitSeal<Txid> {
#[inline]
pub fn to_outpoint(&self) -> Outpoint { Outpoint::new(self.txid, self.vout.into_u32()) }
}
#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum ParseError {
TxidRequired,
WrongTxid(HexToArrayError),
WrongVout,
WrongStructure,
}
impl<Id: SealTxid> FromStr for ExplicitSeal<Id> {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut split = s.split(&[':', '#'][..]);
match (split.next(), split.next(), split.next()) {
(Some(""), ..) => Err(ParseError::TxidRequired),
(Some(txid), Some(vout), None) => Ok(ExplicitSeal {
txid: Id::from_str(txid).map_err(ParseError::WrongTxid)?,
vout: vout.parse().map_err(|_| ParseError::WrongVout)?,
}),
_ => Err(ParseError::WrongStructure),
}
}
}
impl<Id: SealTxid> Display for ExplicitSeal<Id> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.txid, self.vout,)
}
}