use std::collections::{BTreeMap, HashSet};
use elements::AssetId;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Balance(BTreeMap<AssetId, u64>);
impl From<BTreeMap<AssetId, u64>> for Balance {
fn from(map: BTreeMap<AssetId, u64>) -> Self {
Self(map)
}
}
impl AsRef<BTreeMap<AssetId, u64>> for Balance {
fn as_ref(&self) -> &BTreeMap<AssetId, u64> {
&self.0
}
}
impl std::ops::Deref for Balance {
type Target = BTreeMap<AssetId, u64>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::Sub<Balance> for Balance {
type Output = SignedBalance;
fn sub(self, other: Balance) -> SignedBalance {
let all_keys: HashSet<_> = other.0.keys().chain(self.0.keys()).collect();
let mut result = BTreeMap::new();
for key in all_keys {
result.insert(
*key,
self.0.get(key).cloned().unwrap_or(0) as i64
- other.0.get(key).cloned().unwrap_or(0) as i64,
);
}
result.retain(|_, v| *v != 0);
SignedBalance(result)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(transparent)]
pub struct SignedBalance(BTreeMap<AssetId, i64>);
impl From<BTreeMap<AssetId, i64>> for SignedBalance {
fn from(map: BTreeMap<AssetId, i64>) -> Self {
Self(map)
}
}
impl AsRef<BTreeMap<AssetId, i64>> for SignedBalance {
fn as_ref(&self) -> &BTreeMap<AssetId, i64> {
&self.0
}
}
impl std::ops::Deref for SignedBalance {
type Target = BTreeMap<AssetId, i64>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::*;
#[test]
fn test_balance_subtraction() {
use std::collections::BTreeMap;
let a = |a| AssetId::from_str(a).unwrap();
let policy_asset =
AssetId::from_str("5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225")
.unwrap();
let asset1 = policy_asset;
let asset2 = a("6f0279e9ed041c3d710a9f57d0c02928416460c4b722d5a6d002dcab7c5b5b5b");
let asset3 = a("7f0279e9ed041c3d710a9f57d0c02928416460c4b722d5a6d002dcab7c5b5b5b");
let mut balance1 = BTreeMap::new();
balance1.insert(asset1, 1000);
balance1.insert(asset2, 500);
let mut balance2 = BTreeMap::new();
balance2.insert(asset1, 300);
balance2.insert(asset2, 200);
let result = Balance(balance1.clone()) - Balance(balance2.clone());
assert_eq!(result.get(&asset1), Some(&700));
assert_eq!(result.get(&asset2), Some(&300));
let mut balance3 = BTreeMap::new();
balance3.insert(asset1, 1000);
balance3.insert(asset2, 500);
let mut balance4 = BTreeMap::new();
balance4.insert(asset1, 300);
balance4.insert(asset3, 100);
let result2 = Balance(balance3) - Balance(balance4);
assert_eq!(result2.get(&asset1), Some(&700));
assert_eq!(result2.get(&asset2), Some(&500)); assert_eq!(result2.get(&asset3), Some(&-100));
let mut balance5 = BTreeMap::new();
balance5.insert(asset1, 500);
let mut balance6 = BTreeMap::new();
balance6.insert(asset1, 500);
let result3 = Balance::from(balance5) - Balance::from(balance6);
assert_eq!(result3.get(&asset1), None);
let empty_balance = Balance::from(BTreeMap::new());
let result4 = Balance::from(balance1) - empty_balance.clone();
assert_eq!(result4.get(&asset1), Some(&1000));
assert_eq!(result4.get(&asset2), Some(&500));
let result5 = empty_balance - Balance::from(balance2);
assert_eq!(result5.get(&asset1), Some(&-300));
assert_eq!(result5.get(&asset2), Some(&-200));
let mut balance7 = BTreeMap::new();
balance7.insert(asset1, 100);
let mut balance8 = BTreeMap::new();
balance8.insert(asset1, 300);
let result6 = Balance::from(balance7) - Balance::from(balance8);
assert_eq!(result6.get(&asset1), Some(&-200));
}
}