use strum::VariantArray;
#[derive(
Clone,
Copy,
Debug,
Hash,
PartialEq,
Eq,
strum::VariantArray,
strum::IntoStaticStr,
strum::EnumString,
strum::FromRepr,
serde::Serialize,
serde::Deserialize,
)]
#[strum(serialize_all = "kebab-case")]
#[repr(i32)]
pub enum PackageState {
PreSkipped = 0,
PreFailed = 1,
Unresolved = 2,
IndirectPreSkipped = 3,
IndirectPreFailed = 4,
IndirectUnresolved = 5,
Pending = 6,
UpToDate = 7,
Success = 8,
Failed = 9,
IndirectFailed = 10,
}
impl PackageState {
pub fn id(self) -> i32 {
self as i32
}
pub fn as_str(self) -> &'static str {
self.into()
}
pub fn as_pbulk_str(self) -> &'static str {
match self {
Self::PreSkipped | Self::PreFailed | Self::Unresolved => "prefailed",
Self::IndirectPreSkipped | Self::IndirectPreFailed | Self::IndirectUnresolved => {
"indirect-prefailed"
}
Self::Pending => "open",
Self::UpToDate | Self::Success => "done",
Self::Failed => "failed",
Self::IndirectFailed => "indirect-failed",
}
}
pub fn desc(self) -> &'static str {
match self {
Self::PreSkipped => "Package has PKG_SKIP_REASON set",
Self::PreFailed => "Package has PKG_FAIL_REASON set",
Self::Unresolved => {
"Package has unresolved dependencies, or could not otherwise be scanned"
}
Self::IndirectPreSkipped => "Package is blocked by a PreSkipped dependency",
Self::IndirectPreFailed => "Package is blocked by a PreFailed dependency",
Self::IndirectUnresolved => "Package is blocked by an Unresolved dependency",
Self::Pending => "Package is buildable, awaiting build",
Self::UpToDate => "Binary package already exists and is current",
Self::Success => "Package built successfully",
Self::Failed => "Package build was attempted but failed",
Self::IndirectFailed => "Package is blocked by a Failed dependency",
}
}
pub fn is_success(self) -> bool {
matches!(self, Self::Success | Self::UpToDate)
}
pub fn is_skipped(self) -> bool {
matches!(self, Self::PreSkipped | Self::PreFailed)
}
pub fn is_blocked(self) -> bool {
matches!(
self,
Self::IndirectPreSkipped
| Self::IndirectPreFailed
| Self::IndirectUnresolved
| Self::IndirectFailed
)
}
pub fn is_masked(self) -> bool {
self.is_skipped() || self.is_blocked()
}
pub fn indirect(self) -> Self {
match self {
Self::PreSkipped | Self::IndirectPreSkipped => Self::IndirectPreSkipped,
Self::PreFailed | Self::IndirectPreFailed => Self::IndirectPreFailed,
Self::Unresolved | Self::IndirectUnresolved => Self::IndirectUnresolved,
_ => self,
}
}
}
impl TryFrom<i32> for PackageState {
type Error = String;
fn try_from(id: i32) -> Result<Self, Self::Error> {
Self::from_repr(id).ok_or_else(|| format!("unknown outcome id {id}"))
}
}
#[derive(Clone, Debug)]
pub struct PackageCounts([usize; PackageState::VARIANTS.len()]);
impl Default for PackageCounts {
fn default() -> Self {
Self([0; PackageState::VARIANTS.len()])
}
}
impl PackageCounts {
pub fn add(&mut self, state: PackageState) {
self.0[state as usize] += 1;
}
pub fn count(&self, pred: impl Fn(PackageState) -> bool) -> usize {
PackageState::VARIANTS
.iter()
.copied()
.filter(|k| pred(*k))
.map(|k| self[k])
.sum()
}
pub fn successful(&self) -> usize {
self.count(PackageState::is_success)
}
pub fn failed(&self) -> usize {
self[PackageState::Failed]
}
pub fn masked(&self) -> usize {
self.count(PackageState::is_masked)
}
pub fn total(&self) -> usize {
self.successful() + self.failed() + self.masked()
}
}
impl std::ops::Index<PackageState> for PackageCounts {
type Output = usize;
fn index(&self, state: PackageState) -> &usize {
&self.0[state as usize]
}
}