use std::sync::Arc;
use parking_lot::RwLock;
use crate::lengths::Lengths;
#[derive(Clone, Default)]
pub struct SafeLengths(Arc<RwLock<Lengths>>);
impl SafeLengths {
pub fn new() -> Self {
Self::default()
}
pub fn load(&self) -> Lengths {
self.0.read().clone()
}
pub fn reset(&self) {
*self.0.write() = Lengths::default();
}
pub fn advance(&self, next: Lengths) {
let mut g = self.0.write();
debug_assert!(
next.height >= g.height
&& next.tx_index >= g.tx_index
&& next.txin_index >= g.txin_index
&& next.txout_index >= g.txout_index
&& next.empty_output_index >= g.empty_output_index
&& next.op_return_index >= g.op_return_index
&& next.p2ms_output_index >= g.p2ms_output_index
&& next.p2pk33_addr_index >= g.p2pk33_addr_index
&& next.p2pk65_addr_index >= g.p2pk65_addr_index
&& next.p2pkh_addr_index >= g.p2pkh_addr_index
&& next.p2sh_addr_index >= g.p2sh_addr_index
&& next.p2tr_addr_index >= g.p2tr_addr_index
&& next.p2wpkh_addr_index >= g.p2wpkh_addr_index
&& next.p2wsh_addr_index >= g.p2wsh_addr_index
&& next.p2a_addr_index >= g.p2a_addr_index
&& next.unknown_output_index >= g.unknown_output_index,
"advance: per-field regression"
);
*g = next;
}
pub fn lower_before(&self, starting: &Lengths) {
let mut g = self.0.write();
g.height = g.height.min(starting.height);
g.tx_index = g.tx_index.min(starting.tx_index);
g.txin_index = g.txin_index.min(starting.txin_index);
g.txout_index = g.txout_index.min(starting.txout_index);
g.empty_output_index = g.empty_output_index.min(starting.empty_output_index);
g.op_return_index = g.op_return_index.min(starting.op_return_index);
g.p2ms_output_index = g.p2ms_output_index.min(starting.p2ms_output_index);
g.p2pk33_addr_index = g.p2pk33_addr_index.min(starting.p2pk33_addr_index);
g.p2pk65_addr_index = g.p2pk65_addr_index.min(starting.p2pk65_addr_index);
g.p2pkh_addr_index = g.p2pkh_addr_index.min(starting.p2pkh_addr_index);
g.p2sh_addr_index = g.p2sh_addr_index.min(starting.p2sh_addr_index);
g.p2tr_addr_index = g.p2tr_addr_index.min(starting.p2tr_addr_index);
g.p2wpkh_addr_index = g.p2wpkh_addr_index.min(starting.p2wpkh_addr_index);
g.p2wsh_addr_index = g.p2wsh_addr_index.min(starting.p2wsh_addr_index);
g.p2a_addr_index = g.p2a_addr_index.min(starting.p2a_addr_index);
g.unknown_output_index = g.unknown_output_index.min(starting.unknown_output_index);
}
}
#[cfg(test)]
mod tests {
use brk_types::{
EmptyOutputIndex, Height, OpReturnIndex, P2AAddrIndex, P2MSOutputIndex, P2PK33AddrIndex,
P2PK65AddrIndex, P2PKHAddrIndex, P2SHAddrIndex, P2TRAddrIndex, P2WPKHAddrIndex,
P2WSHAddrIndex, TxInIndex, TxIndex, TxOutIndex, UnknownOutputIndex,
};
use super::*;
#[test]
fn lower_before_clamps_every_field() {
let sentinel = u32::MAX as usize;
let max = Lengths {
empty_output_index: EmptyOutputIndex::from(sentinel),
height: Height::from(sentinel),
op_return_index: OpReturnIndex::from(sentinel),
p2ms_output_index: P2MSOutputIndex::from(sentinel),
p2pk33_addr_index: P2PK33AddrIndex::from(sentinel),
p2pk65_addr_index: P2PK65AddrIndex::from(sentinel),
p2pkh_addr_index: P2PKHAddrIndex::from(sentinel),
p2sh_addr_index: P2SHAddrIndex::from(sentinel),
p2tr_addr_index: P2TRAddrIndex::from(sentinel),
p2wpkh_addr_index: P2WPKHAddrIndex::from(sentinel),
p2wsh_addr_index: P2WSHAddrIndex::from(sentinel),
p2a_addr_index: P2AAddrIndex::from(sentinel),
tx_index: TxIndex::from(sentinel),
txin_index: TxInIndex::from(sentinel),
txout_index: TxOutIndex::from(sentinel),
unknown_output_index: UnknownOutputIndex::from(sentinel),
};
let safe = SafeLengths::new();
safe.advance(max);
safe.lower_before(&Lengths::default());
assert_eq!(safe.load(), Lengths::default());
}
}