use bpstd::psbt::Utxo;
use bpstd::{Idx, Keychain, NormalIndex, Outpoint, Sats, Terminal};
use indexmap::IndexMap;
#[allow(clippy::len_without_is_empty)]
pub trait UtxoSet {
fn len(&self) -> usize;
fn has(&self, outpoint: Outpoint) -> bool;
fn get(&self, outpoint: Outpoint) -> Option<(Sats, Terminal)>;
#[cfg(not(feature = "async"))]
fn insert(&mut self, outpoint: Outpoint, value: Sats, terminal: Terminal);
#[cfg(feature = "async")]
async fn insert_async(&mut self, outpoint: Outpoint, value: Sats, terminal: Terminal);
#[cfg(not(feature = "async"))]
fn insert_all(&mut self, utxos: impl IntoIterator<Item = Utxo>);
#[cfg(feature = "async")]
async fn insert_all_async(&mut self, utxos: impl IntoIterator<Item = Utxo>);
#[cfg(not(feature = "async"))]
fn clear(&mut self);
#[cfg(feature = "async")]
async fn clear_async(&mut self);
#[cfg(not(feature = "async"))]
fn remove(&mut self, outpoint: Outpoint) -> Option<(Sats, Terminal)>;
#[cfg(feature = "async")]
async fn remove_async(&mut self, outpoint: Outpoint) -> Option<(Sats, Terminal)>;
#[cfg(not(feature = "async"))]
fn remove_all(&mut self, outpoints: impl IntoIterator<Item = Outpoint>);
#[cfg(feature = "async")]
async fn remove_all_async(&mut self, outpoints: impl IntoIterator<Item = Outpoint>);
fn outpoints(&self) -> impl Iterator<Item = Outpoint>;
fn next_index_noshift(&self, keychain: impl Into<Keychain>) -> NormalIndex;
#[cfg(not(feature = "async"))]
fn next_index(&mut self, keychain: impl Into<Keychain>, shift: bool) -> NormalIndex;
#[cfg(feature = "async")]
async fn next_index_async(&mut self, keychain: impl Into<Keychain>, shift: bool)
-> NormalIndex;
}
#[derive(Clone, PartialEq, Eq, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
pub struct MemUtxos {
set: IndexMap<Outpoint, (Sats, Terminal)>,
next_index: IndexMap<Keychain, NormalIndex>,
}
impl UtxoSet for MemUtxos {
#[inline]
fn len(&self) -> usize { self.set.len() }
#[inline]
fn has(&self, outpoint: Outpoint) -> bool { self.set.contains_key(&outpoint) }
#[inline]
fn get(&self, outpoint: Outpoint) -> Option<(Sats, Terminal)> {
self.set.get(&outpoint).copied()
}
#[inline]
#[cfg(not(feature = "async"))]
fn insert(&mut self, outpoint: Outpoint, value: Sats, terminal: Terminal) {
self.set.insert(outpoint, (value, terminal));
}
#[inline]
#[cfg(feature = "async")]
async fn insert_async(&mut self, outpoint: Outpoint, value: Sats, terminal: Terminal) {
self.set.insert(outpoint, (value, terminal));
}
#[inline]
#[cfg(not(feature = "async"))]
fn insert_all(&mut self, utxos: impl IntoIterator<Item = Utxo>) {
for utxo in utxos {
self.set.insert(utxo.outpoint, (utxo.value, utxo.terminal));
}
}
#[inline]
#[cfg(feature = "async")]
async fn insert_all_async(&mut self, utxos: impl IntoIterator<Item = Utxo>) {
for utxo in utxos {
self.set.insert(utxo.outpoint, (utxo.value, utxo.terminal));
}
}
#[inline]
#[cfg(not(feature = "async"))]
fn clear(&mut self) { self.set.clear() }
#[inline]
#[cfg(feature = "async")]
async fn clear_async(&mut self) { self.set.clear() }
#[inline]
#[cfg(not(feature = "async"))]
fn remove(&mut self, outpoint: Outpoint) -> Option<(Sats, Terminal)> {
self.set.shift_remove(&outpoint)
}
#[inline]
#[cfg(feature = "async")]
async fn remove_async(&mut self, outpoint: Outpoint) -> Option<(Sats, Terminal)> {
self.set.shift_remove(&outpoint)
}
#[inline]
#[cfg(not(feature = "async"))]
fn remove_all(&mut self, outpoints: impl IntoIterator<Item = Outpoint>) {
for outpoint in outpoints {
self.set.shift_remove(&outpoint);
}
}
#[inline]
#[cfg(feature = "async")]
async fn remove_all_async(&mut self, outpoints: impl IntoIterator<Item = Outpoint>) {
for outpoint in outpoints {
self.set.shift_remove(&outpoint);
}
}
#[inline]
fn outpoints(&self) -> impl Iterator<Item = Outpoint> { self.set.keys().copied() }
fn next_index_noshift(&self, keychain: impl Into<Keychain>) -> NormalIndex {
self.next_index
.get(&keychain.into())
.copied()
.unwrap_or_default()
}
#[cfg(not(feature = "async"))]
fn next_index(&mut self, keychain: impl Into<Keychain>, shift: bool) -> NormalIndex {
let index = self.next_index.entry(keychain.into()).or_default();
let next = *index;
if shift {
index.saturating_inc_assign();
}
next
}
#[inline]
#[cfg(feature = "async")]
async fn next_index_async(
&mut self,
keychain: impl Into<Keychain>,
shift: bool,
) -> NormalIndex {
let index = self.next_index.entry(keychain.into()).or_default();
let next = *index;
if shift {
index.saturating_inc_assign();
}
next
}
}