use std::str::FromStr;
use strum::{EnumCount, IntoEnumIterator};
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
strum::EnumCount,
strum::EnumIter,
strum::EnumString,
strum::FromRepr,
strum::AsRefStr,
strum::IntoStaticStr,
)]
#[strum(serialize_all = "kebab-case")]
#[repr(i32)]
pub enum PackageStateKind {
PreSkipped = 0,
PreFailed = 1,
Unresolved = 2,
IndirectPreSkipped = 3,
IndirectPreFailed = 4,
IndirectUnresolved = 5,
Pending = 6,
UpToDate = 7,
Success = 8,
Failed = 9,
IndirectFailed = 10,
}
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum PackageState {
PreSkipped(String),
PreFailed(String),
Unresolved(String),
IndirectPreSkipped(String),
IndirectPreFailed(String),
IndirectUnresolved(String),
Pending,
UpToDate,
Success,
Failed(String),
IndirectFailed(String),
}
impl PackageState {
pub fn kind(&self) -> PackageStateKind {
match self {
Self::PreSkipped(_) => PackageStateKind::PreSkipped,
Self::PreFailed(_) => PackageStateKind::PreFailed,
Self::Unresolved(_) => PackageStateKind::Unresolved,
Self::IndirectPreSkipped(_) => PackageStateKind::IndirectPreSkipped,
Self::IndirectPreFailed(_) => PackageStateKind::IndirectPreFailed,
Self::IndirectUnresolved(_) => PackageStateKind::IndirectUnresolved,
Self::Pending => PackageStateKind::Pending,
Self::UpToDate => PackageStateKind::UpToDate,
Self::Success => PackageStateKind::Success,
Self::Failed(_) => PackageStateKind::Failed,
Self::IndirectFailed(_) => PackageStateKind::IndirectFailed,
}
}
fn from_kind(kind: PackageStateKind, detail: String) -> Self {
match kind {
PackageStateKind::PreSkipped => Self::PreSkipped(detail),
PackageStateKind::PreFailed => Self::PreFailed(detail),
PackageStateKind::Unresolved => Self::Unresolved(detail),
PackageStateKind::IndirectPreSkipped => Self::IndirectPreSkipped(detail),
PackageStateKind::IndirectPreFailed => Self::IndirectPreFailed(detail),
PackageStateKind::IndirectUnresolved => Self::IndirectUnresolved(detail),
PackageStateKind::Pending => Self::Pending,
PackageStateKind::UpToDate => Self::UpToDate,
PackageStateKind::Success => Self::Success,
PackageStateKind::Failed => Self::Failed(detail),
PackageStateKind::IndirectFailed => Self::IndirectFailed(detail),
}
}
pub fn status(&self) -> &'static str {
self.kind().into()
}
pub fn db_id(&self) -> i32 {
self.kind() as i32
}
pub fn from_db(id: i32, detail: Option<String>) -> Option<Self> {
PackageStateKind::from_repr(id).map(|k| Self::from_kind(k, detail.unwrap_or_default()))
}
pub fn from_status(s: &str) -> Option<Self> {
PackageStateKind::from_str(s)
.ok()
.map(|k| Self::from_kind(k, String::new()))
}
pub fn detail(&self) -> Option<&str> {
match self {
Self::Pending | Self::UpToDate | Self::Success => None,
Self::PreSkipped(s)
| Self::PreFailed(s)
| Self::Unresolved(s)
| Self::IndirectPreSkipped(s)
| Self::IndirectPreFailed(s)
| Self::IndirectUnresolved(s)
| Self::Failed(s)
| Self::IndirectFailed(s) => Some(s),
}
}
pub fn is_skip(&self) -> bool {
!matches!(self, Self::Success | Self::Failed(_) | Self::UpToDate)
}
pub fn is_direct_skip(&self) -> bool {
matches!(
self,
Self::PreSkipped(_) | Self::PreFailed(_) | Self::Unresolved(_)
)
}
pub fn indirect(&self, detail: String) -> Self {
match self {
Self::PreSkipped(_) | Self::IndirectPreSkipped(_) => Self::IndirectPreSkipped(detail),
Self::PreFailed(_) | Self::IndirectPreFailed(_) => Self::IndirectPreFailed(detail),
Self::Unresolved(_) | Self::IndirectUnresolved(_) => Self::IndirectUnresolved(detail),
Self::IndirectFailed(_) => Self::IndirectFailed(detail),
other => other.clone(),
}
}
pub fn db_values() -> String {
PackageStateKind::iter()
.filter(|k| *k != PackageStateKind::Pending)
.map(|k| {
let s: &'static str = k.into();
format!("({}, '{}')", k as i32, s)
})
.collect::<Vec<_>>()
.join(", ")
}
}
#[derive(Clone, Debug)]
pub struct PackageCounts([usize; PackageStateKind::COUNT]);
impl Default for PackageCounts {
fn default() -> Self {
Self([0; PackageStateKind::COUNT])
}
}
impl PackageCounts {
pub fn add(&mut self, state: &PackageState) {
self.0[state.kind() as usize] += 1;
}
}
impl std::ops::Index<PackageStateKind> for PackageCounts {
type Output = usize;
fn index(&self, kind: PackageStateKind) -> &usize {
&self.0[kind as usize]
}
}
impl std::fmt::Display for PackageState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Unresolved(detail) => write!(f, "Could not resolve: {}", detail),
other => match other.detail() {
Some(d) if !d.is_empty() => write!(f, "{}", d),
_ => write!(f, "{}", other.status()),
},
}
}
}