use std::fmt::{self, Debug}; use brk_core::{ DateIndex, DecadeIndex, DifficultyEpoch, EmptyOutputIndex, HalvingEpoch, Height, InputIndex, MonthIndex, OpReturnIndex, OutputIndex, P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, Printable, QuarterIndex, SemesterIndex, TxIndex, UnknownOutputIndex, WeekIndex, YearIndex, }; use color_eyre::eyre::eyre; use schemars::JsonSchema; use serde::{Deserialize, de::Error}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, JsonSchema)] pub enum Index { #[schemars(description = "Date/day index")] DateIndex, #[schemars(description = "Decade index")] DecadeIndex, #[schemars(description = "Difficulty epoch index (equivalent to ~2 weeks)")] DifficultyEpoch, #[schemars(description = "Empty output index")] EmptyOutputIndex, #[schemars(description = "Halving epoch index (equivalent to ~4 years)")] HalvingEpoch, #[schemars(description = "Height/block index")] Height, #[schemars(description = "Transaction input index (based on total)")] InputIndex, #[schemars(description = "Month index")] MonthIndex, #[schemars(description = "Op return index")] OpReturnIndex, #[schemars(description = "Transaction output index (based on total)")] OutputIndex, #[schemars(description = "Index of P2A address")] P2AAddressIndex, #[schemars(description = "Index of P2MS output")] P2MSOutputIndex, #[schemars(description = "Index of P2PK (33 bytes) address")] P2PK33AddressIndex, #[schemars(description = "Index of P2PK (65 bytes) address")] P2PK65AddressIndex, #[schemars(description = "Index of P2PKH address")] P2PKHAddressIndex, #[schemars(description = "Index of P2SH address")] P2SHAddressIndex, #[schemars(description = "Index of P2TR address")] P2TRAddressIndex, #[schemars(description = "Index of P2WPKH address")] P2WPKHAddressIndex, #[schemars(description = "Index of P2WSH address")] P2WSHAddressIndex, #[schemars(description = "Quarter index")] QuarterIndex, #[schemars(description = "Semester index")] SemesterIndex, #[schemars(description = "Transaction index")] TxIndex, #[schemars(description = "Unknown output index")] UnknownOutputIndex, #[schemars(description = "Week index")] WeekIndex, #[schemars(description = "Year index")] YearIndex, } impl Index { pub fn all() -> [Self; 25] { [ Self::DateIndex, Self::DecadeIndex, Self::DifficultyEpoch, Self::EmptyOutputIndex, Self::HalvingEpoch, Self::Height, Self::InputIndex, Self::MonthIndex, Self::OpReturnIndex, Self::OutputIndex, Self::P2AAddressIndex, Self::P2MSOutputIndex, Self::P2PK33AddressIndex, Self::P2PK65AddressIndex, Self::P2PKHAddressIndex, Self::P2SHAddressIndex, Self::P2TRAddressIndex, Self::P2WPKHAddressIndex, Self::P2WSHAddressIndex, Self::QuarterIndex, Self::SemesterIndex, Self::TxIndex, Self::UnknownOutputIndex, Self::WeekIndex, Self::YearIndex, ] } pub fn possible_values(&self) -> &'static [&'static str] { match self { Self::DateIndex => DateIndex::to_possible_strings(), Self::DecadeIndex => DecadeIndex::to_possible_strings(), Self::DifficultyEpoch => DifficultyEpoch::to_possible_strings(), Self::EmptyOutputIndex => EmptyOutputIndex::to_possible_strings(), Self::HalvingEpoch => HalvingEpoch::to_possible_strings(), Self::Height => Height::to_possible_strings(), Self::InputIndex => InputIndex::to_possible_strings(), Self::MonthIndex => MonthIndex::to_possible_strings(), Self::OpReturnIndex => OpReturnIndex::to_possible_strings(), Self::OutputIndex => OutputIndex::to_possible_strings(), Self::P2AAddressIndex => P2AAddressIndex::to_possible_strings(), Self::P2MSOutputIndex => P2MSOutputIndex::to_possible_strings(), Self::P2PK33AddressIndex => P2PK33AddressIndex::to_possible_strings(), Self::P2PK65AddressIndex => P2PK65AddressIndex::to_possible_strings(), Self::P2PKHAddressIndex => P2PKHAddressIndex::to_possible_strings(), Self::P2SHAddressIndex => P2SHAddressIndex::to_possible_strings(), Self::P2TRAddressIndex => P2TRAddressIndex::to_possible_strings(), Self::P2WPKHAddressIndex => P2WPKHAddressIndex::to_possible_strings(), Self::P2WSHAddressIndex => P2WSHAddressIndex::to_possible_strings(), Self::QuarterIndex => QuarterIndex::to_possible_strings(), Self::SemesterIndex => SemesterIndex::to_possible_strings(), Self::TxIndex => TxIndex::to_possible_strings(), Self::UnknownOutputIndex => UnknownOutputIndex::to_possible_strings(), Self::WeekIndex => WeekIndex::to_possible_strings(), Self::YearIndex => YearIndex::to_possible_strings(), } } pub fn all_possible_values() -> Vec<&'static str> { Self::all() .into_iter() .flat_map(|i| i.possible_values().iter().cloned()) .collect::>() } pub fn serialize_short(&self) -> &'static str { self.possible_values() .iter() .find(|str| str.len() > 1) .unwrap() } pub fn serialize_long(&self) -> &'static str { self.possible_values().last().unwrap() } } impl TryFrom<&str> for Index { type Error = color_eyre::Report; fn try_from(value: &str) -> Result { Ok(match value.to_lowercase().as_str() { v if (Self::DateIndex).possible_values().contains(&v) => Self::DateIndex, v if (Self::DecadeIndex).possible_values().contains(&v) => Self::DecadeIndex, v if (Self::DifficultyEpoch).possible_values().contains(&v) => Self::DifficultyEpoch, v if (Self::EmptyOutputIndex).possible_values().contains(&v) => Self::EmptyOutputIndex, v if (Self::HalvingEpoch).possible_values().contains(&v) => Self::HalvingEpoch, v if (Self::Height).possible_values().contains(&v) => Self::Height, v if (Self::InputIndex).possible_values().contains(&v) => Self::InputIndex, v if (Self::MonthIndex).possible_values().contains(&v) => Self::MonthIndex, v if (Self::OpReturnIndex).possible_values().contains(&v) => Self::OpReturnIndex, v if (Self::OutputIndex).possible_values().contains(&v) => Self::OutputIndex, v if (Self::P2AAddressIndex).possible_values().contains(&v) => Self::P2AAddressIndex, v if (Self::P2MSOutputIndex).possible_values().contains(&v) => Self::P2MSOutputIndex, v if (Self::P2PK33AddressIndex).possible_values().contains(&v) => { Self::P2PK33AddressIndex } v if (Self::P2PK65AddressIndex).possible_values().contains(&v) => { Self::P2PK65AddressIndex } v if (Self::P2PKHAddressIndex).possible_values().contains(&v) => { Self::P2PKHAddressIndex } v if (Self::P2SHAddressIndex).possible_values().contains(&v) => Self::P2SHAddressIndex, v if (Self::P2TRAddressIndex).possible_values().contains(&v) => Self::P2TRAddressIndex, v if (Self::P2WPKHAddressIndex).possible_values().contains(&v) => { Self::P2WPKHAddressIndex } v if (Self::P2WSHAddressIndex).possible_values().contains(&v) => { Self::P2WSHAddressIndex } v if (Self::QuarterIndex).possible_values().contains(&v) => Self::QuarterIndex, v if (Self::SemesterIndex).possible_values().contains(&v) => Self::SemesterIndex, v if (Self::TxIndex).possible_values().contains(&v) => Self::TxIndex, v if (Self::WeekIndex).possible_values().contains(&v) => Self::WeekIndex, v if (Self::YearIndex).possible_values().contains(&v) => Self::YearIndex, v if (Self::UnknownOutputIndex).possible_values().contains(&v) => { Self::UnknownOutputIndex } _ => return Err(eyre!("Bad index")), }) } } impl fmt::Display for Index { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{self:?}") } } impl<'de> Deserialize<'de> for Index { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let str = String::deserialize(deserializer)?; if let Ok(index) = Index::try_from(str.as_str()) { // dbg!(index); Ok(index) } else { Err(Error::custom("Bad index")) } } }