use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Status {
#[serde(rename = "uncooked")]
Uncooked,
#[serde(rename = "cooked")]
Cooked {
#[serde(default, skip_serializing_if = "Option::is_none")]
phase: Option<CookedPhase>,
#[serde(default, skip_serializing_if = "Option::is_none")]
detail: Option<StatusDetail>,
},
#[serde(rename = "done")]
Done {
#[serde(default, skip_serializing_if = "Option::is_none")]
outcome: Option<DoneOutcome>,
},
#[serde(rename = "evergreen")]
Evergreen,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CookedPhase {
Active,
Waiting,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DoneOutcome {
Completed,
Abandoned,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StatusDetail {
pub source: String,
pub label: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub info: Option<serde_json::Value>,
}
pub fn is_cookbook_settable(status: &Status) -> bool {
matches!(status, Status::Done { .. } | Status::Evergreen)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cookbook_settable_allows_done_and_evergreen_only() {
assert!(is_cookbook_settable(&Status::Done { outcome: None }));
assert!(is_cookbook_settable(&Status::Evergreen));
assert!(!is_cookbook_settable(&Status::Uncooked));
assert!(!is_cookbook_settable(&Status::Cooked {
phase: Some(CookedPhase::Active),
detail: None
}));
}
#[test]
fn status_roundtrips_through_json() {
let s = Status::Done {
outcome: Some(DoneOutcome::Completed),
};
let json = serde_json::to_string(&s).unwrap();
assert_eq!(serde_json::from_str::<Status>(&json).unwrap(), s);
}
}