use bitcoin::Amount;
use chrono::{DateTime, Local};
use crate::vtxo::VtxoStateKind;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct SortKey(Vec<u8>);
impl SortKey {
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn from_bytes(bytes: Vec<u8>) -> Self {
Self(bytes)
}
pub fn builder() -> SortKeyBuilder {
SortKeyBuilder(Vec::new())
}
pub fn u32_asc(n: u32) -> Self {
Self::builder().u32_asc(n).build()
}
pub fn u64_desc(n: u64) -> Self {
Self::builder().u64_desc(n).build()
}
}
#[derive(Debug, Clone, Default)]
pub struct SortKeyBuilder(Vec<u8>);
impl SortKeyBuilder {
pub fn u8_asc(mut self, n: u8) -> Self {
self.0.push(n);
self
}
pub fn u32_asc(mut self, n: u32) -> Self {
self.0.extend_from_slice(&n.to_be_bytes());
self
}
pub fn u64_desc(mut self, n: u64) -> Self {
self.0.extend_from_slice(&(!n).to_be_bytes());
self
}
pub fn build(self) -> SortKey {
SortKey(self.0)
}
}
pub(crate) fn vtxo_sort_key(vtxo_state: VtxoStateKind, expiry_height: u32, amount: Amount) -> SortKey {
SortKey::builder()
.u8_asc(vtxo_state.as_byte())
.u32_asc(expiry_height)
.u64_desc(amount.to_sat())
.build()
}
pub(crate) fn movement_sort_key(created_at: &DateTime<Local>) -> SortKey {
SortKey::u64_desc(created_at.timestamp_millis() as u64)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sort_key_u64() {
let k1 = SortKey::builder().u32_asc(1).build();
let k2 = SortKey::builder().u32_asc(2).build();
let k3 = SortKey::builder().u32_asc(3).build();
assert!(k1 < k2);
assert!(k2 < k3);
assert!(k1 < k3);
}
#[test]
fn sort_key_u64_desc() {
let k1 = SortKey::builder().u64_desc(1).build();
let k2 = SortKey::builder().u64_desc(2).build();
let k3 = SortKey::builder().u64_desc(3).build();
assert!(k1 > k2);
assert!(k2 > k3);
assert!(k1 > k3);
}
#[test]
fn sort_key_composite() {
let make_key = |height: u32, amount: u64| {
SortKey::builder()
.u32_asc(height)
.u64_desc(amount)
.build()
};
let k1 = make_key(100, 1000);
let k2 = make_key(100, 500);
assert!(k1 < k2);
let k3 = make_key(50, 100);
assert!(k3 < k1);
assert!(k3 < k2);
let k4 = make_key(150, 100);
assert!(k4 > k1);
assert!(k4 > k2);
assert!(k4 > k3);
}
}