1use alloc::string::String;
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
12pub enum ApprovalKind {
13 Spawn,
15 ToolUse,
17 BudgetIncrease,
19 Custom(String),
21}
22
23impl ApprovalKind {
24 pub fn as_str(&self) -> &str {
26 match self {
27 Self::Spawn => "spawn",
28 Self::ToolUse => "tool_use",
29 Self::BudgetIncrease => "budget_increase",
30 Self::Custom(s) => s.as_str(),
31 }
32 }
33}
34
35impl core::fmt::Display for ApprovalKind {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 f.write_str(self.as_str())
38 }
39}
40
41impl core::str::FromStr for ApprovalKind {
42 type Err = core::convert::Infallible;
43
44 fn from_str(s: &str) -> Result<Self, Self::Err> {
45 Ok(match s {
46 "spawn" => Self::Spawn,
47 "tool_use" => Self::ToolUse,
48 "budget_increase" => Self::BudgetIncrease,
49 other => Self::Custom(String::from(other)),
50 })
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn known_kinds_round_trip_via_as_str_and_from_str() {
60 for kind in [ApprovalKind::Spawn, ApprovalKind::ToolUse, ApprovalKind::BudgetIncrease] {
61 let s = kind.as_str();
62 let parsed: ApprovalKind = s.parse().unwrap();
63 assert_eq!(kind, parsed);
64 }
65 }
66
67 #[test]
68 fn custom_kind_preserves_string() {
69 let k: ApprovalKind = "file_access".parse().unwrap();
70 assert_eq!(k, ApprovalKind::Custom(String::from("file_access")));
71 assert_eq!(k.as_str(), "file_access");
72 }
73
74 #[test]
75 fn display_matches_as_str() {
76 assert_eq!(ApprovalKind::Spawn.to_string(), "spawn");
77 assert_eq!(ApprovalKind::ToolUse.to_string(), "tool_use");
78 }
79}