use crate::{AsGear, Error, Event, GearConfig, Result, TxInBlock};
use subxt::{blocks::ExtrinsicEvents, utils::H256};
#[derive(Debug, derive_more::AsRef, derive_more::AsMut)]
pub struct TxOutput<T = ()> {
pub block_hash: H256,
pub events: ExtrinsicEvents<GearConfig>,
#[as_ref]
#[as_mut]
pub value: T,
}
impl TxOutput {
pub async fn new(tx: TxInBlock) -> Result<Self> {
Ok(Self {
block_hash: tx.block_hash(),
events: tx.wait_for_success().await?,
value: (),
})
}
pub fn find_map<T, F>(self, mut f: F) -> Result<TxOutput<Option<T>>>
where
F: FnMut(Event) -> Option<T>,
{
let value = self
.events()
.map(move |event| event.map(&mut f))
.find_map(|res| res.transpose())
.transpose()?;
Ok(self.with_value(value))
}
pub fn filter_map<T, F>(self, mut f: F) -> Result<TxOutput<Vec<T>>>
where
F: FnMut(Event) -> Option<T>,
{
let values = self
.events()
.map(move |event| event.map(&mut f))
.filter_map(|res| res.transpose())
.collect::<Result<Vec<_>>>()?;
Ok(self.with_value(values))
}
pub fn any<F>(self, mut f: F) -> Result<TxOutput<bool>>
where
F: FnMut(Event) -> bool,
{
Ok(self
.find_map(move |event| f(event).then_some(()))?
.map(|opt| opt.is_some()))
}
pub fn try_for_each<E, F>(self, mut f: F) -> Result<Self, E>
where
E: From<Error>,
F: FnMut(Event) -> Result<(), E>,
{
self.events().try_for_each(move |event| f(event?))?;
Ok(self)
}
}
impl TxOutput<bool> {
pub fn or<F: FnOnce() -> bool>(self, b: F) -> Self {
self.map(move |opt| opt || b())
}
pub fn then<T, F>(self, f: F) -> TxOutput<Option<T>>
where
F: FnOnce() -> T,
{
self.map(move |opt| opt.then(f))
}
pub fn then_ok(self) -> Result<TxOutput> {
if self.value {
Ok(self.with_value(()))
} else {
Err(Error::EventNotFound)
}
}
}
impl<T> TxOutput<T> {
pub fn events(&self) -> impl Iterator<Item = Result<Event>> {
self.events.iter().map(|event| event?.as_gear())
}
pub fn extrinsic_hash(&self) -> H256 {
self.events.extrinsic_hash()
}
pub fn with_value<O>(self, value: O) -> TxOutput<O> {
TxOutput {
block_hash: self.block_hash,
events: self.events,
value,
}
}
pub fn split(self) -> (TxOutput, T) {
(
TxOutput {
block_hash: self.block_hash,
events: self.events,
value: (),
},
self.value,
)
}
pub fn map<O, F>(self, f: F) -> TxOutput<O>
where
F: FnOnce(T) -> O,
{
let (tx_output, value) = self.split();
tx_output.with_value(f(value))
}
}
impl<T> TxOutput<Option<T>> {
pub fn or_else<F>(self, f: F) -> Self
where
F: FnOnce() -> Option<T>,
{
self.map(move |opt| opt.or_else(f))
}
pub fn ok_or_err(self) -> Result<TxOutput<T>> {
let (tx_output, option) = self.split();
match option {
Some(value) => Ok(tx_output.with_value(value)),
None => Err(Error::EventNotFound),
}
}
}