use anyhow::Context;
use bc_components::ARID;
use bc_envelope::prelude::*;
use std::collections::HashMap;
use crate::{BlockHeight, Indexed, envelope_indexed_objects_for_predicate};
use super::{Transaction, TxId, ZewifWallet};
#[derive(Debug, Clone, PartialEq)]
pub struct Zewif {
id: ARID,
wallets: Vec<ZewifWallet>,
transactions: HashMap<TxId, Transaction>,
export_height: BlockHeight,
attachments: Attachments,
}
bc_envelope::impl_attachable!(Zewif);
impl Zewif {
pub fn new(export_height: BlockHeight) -> Self {
Self {
id: ARID::new(),
wallets: Vec::new(),
transactions: HashMap::new(),
export_height,
attachments: Attachments::new(),
}
}
pub fn id(&self) -> ARID {
self.id
}
pub fn wallets(&self) -> &Vec<ZewifWallet> {
&self.wallets
}
pub fn wallets_len(&self) -> usize {
self.wallets.len()
}
pub fn add_wallet(&mut self, mut wallet: ZewifWallet) {
wallet.set_index(self.wallets_len());
self.wallets.push(wallet);
}
pub fn transactions(&self) -> &HashMap<TxId, Transaction> {
&self.transactions
}
pub fn add_transaction(&mut self, txid: TxId, transaction: Transaction) {
self.transactions.insert(txid, transaction);
}
pub fn get_transaction(&self, txid: TxId) -> Option<&Transaction> {
self.transactions.get(&txid)
}
pub fn set_transactions(&mut self, transactions: HashMap<TxId, Transaction>) {
self.transactions = transactions;
}
pub fn export_height(&self) -> BlockHeight {
self.export_height
}
}
#[rustfmt::skip]
impl From<Zewif> for Envelope {
fn from(value: Zewif) -> Self {
let mut e = Envelope::new(value.id)
.add_type("Zewif");
e = value.wallets.iter().fold(e, |e, wallet| e.add_assertion("wallet", wallet.clone()));
e = value.transactions.iter().fold(e, |e, (_, transaction)| e.add_assertion("transaction", transaction.clone()));
e = e.add_assertion("export_height", value.export_height);
value.attachments.add_to_envelope(e)
}
}
#[rustfmt::skip]
impl TryFrom<Envelope> for Zewif {
type Error = anyhow::Error;
fn try_from(envelope: Envelope) -> Result<Self, Self::Error> {
envelope.check_type_envelope("Zewif")?;
let id = envelope.extract_subject()?;
let wallets = envelope_indexed_objects_for_predicate(&envelope, "wallet")?;
let transactions = envelope
.try_objects_for_predicate::<Transaction>("transaction")?
.into_iter().map(|tx| (tx.txid(), tx)).collect();
let export_height = envelope.extract_object_for_predicate("export_height").context("export_height")?;
let attachments = Attachments::try_from_envelope(&envelope).context("attachments")?;
Ok(Self {
id,
wallets,
transactions,
export_height,
attachments,
})
}
}
#[cfg(test)]
mod tests {
use bc_components::ARID;
use bc_envelope::Attachments;
use crate::{BlockHeight, Transaction, test_envelope_roundtrip};
use super::Zewif;
impl crate::RandomInstance for Zewif {
fn random() -> Self {
use crate::SetIndexes;
Self {
id: ARID::new(),
wallets: Vec::random().set_indexes(),
transactions: Vec::<Transaction>::random()
.iter()
.map(|tx| (tx.txid(), tx.clone()))
.collect(),
export_height: BlockHeight::random(),
attachments: Attachments::random(),
}
}
}
test_envelope_roundtrip!(Zewif);
}