rusty_beads/types/
status.rs1use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::str::FromStr;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
9#[serde(rename_all = "snake_case")]
10pub enum Status {
11 #[default]
13 Open,
14 InProgress,
16 Blocked,
18 Deferred,
20 Closed,
22 Tombstone,
24 Pinned,
26 Hooked,
28}
29
30impl Status {
31 pub fn is_active(&self) -> bool {
33 matches!(self, Status::Open | Status::InProgress | Status::Blocked)
34 }
35
36 pub fn is_terminal(&self) -> bool {
38 matches!(self, Status::Closed | Status::Tombstone)
39 }
40
41 pub fn blocks_dependents(&self) -> bool {
43 !matches!(self, Status::Closed | Status::Tombstone)
44 }
45
46 pub fn all() -> &'static [Status] {
48 &[
49 Status::Open,
50 Status::InProgress,
51 Status::Blocked,
52 Status::Deferred,
53 Status::Closed,
54 Status::Tombstone,
55 Status::Pinned,
56 Status::Hooked,
57 ]
58 }
59
60 pub fn as_str(&self) -> &'static str {
62 match self {
63 Status::Open => "open",
64 Status::InProgress => "in_progress",
65 Status::Blocked => "blocked",
66 Status::Deferred => "deferred",
67 Status::Closed => "closed",
68 Status::Tombstone => "tombstone",
69 Status::Pinned => "pinned",
70 Status::Hooked => "hooked",
71 }
72 }
73}
74
75impl fmt::Display for Status {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 write!(f, "{}", self.as_str())
78 }
79}
80
81impl FromStr for Status {
82 type Err = String;
83
84 fn from_str(s: &str) -> Result<Self, Self::Err> {
85 match s.to_lowercase().as_str() {
86 "open" => Ok(Status::Open),
87 "in_progress" | "in-progress" | "inprogress" => Ok(Status::InProgress),
88 "blocked" => Ok(Status::Blocked),
89 "deferred" => Ok(Status::Deferred),
90 "closed" => Ok(Status::Closed),
91 "tombstone" => Ok(Status::Tombstone),
92 "pinned" => Ok(Status::Pinned),
93 "hooked" => Ok(Status::Hooked),
94 _ => Err(format!("unknown status: {}", s)),
95 }
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_status_roundtrip() {
105 for status in Status::all() {
106 let s = status.as_str();
107 let parsed: Status = s.parse().unwrap();
108 assert_eq!(*status, parsed);
109 }
110 }
111
112 #[test]
113 fn test_status_serde() {
114 let status = Status::InProgress;
115 let json = serde_json::to_string(&status).unwrap();
116 assert_eq!(json, "\"in_progress\"");
117 let parsed: Status = serde_json::from_str(&json).unwrap();
118 assert_eq!(status, parsed);
119 }
120}