Skip to main content

uira_core/protocol/primitives/
event.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
4#[serde(rename_all = "PascalCase")]
5pub enum HookEvent {
6    PreToolUse,
7    PostToolUse,
8    UserPromptSubmit,
9    Stop,
10    PreCompact,
11    PreCheck,
12    PostCheck,
13    PreAi,
14    PostAi,
15    PreFix,
16    PostFix,
17}
18
19impl HookEvent {
20    pub fn as_str(&self) -> &'static str {
21        match self {
22            Self::PreToolUse => "PreToolUse",
23            Self::PostToolUse => "PostToolUse",
24            Self::UserPromptSubmit => "UserPromptSubmit",
25            Self::Stop => "Stop",
26            Self::PreCompact => "PreCompact",
27            Self::PreCheck => "pre-check",
28            Self::PostCheck => "post-check",
29            Self::PreAi => "pre-ai",
30            Self::PostAi => "post-ai",
31            Self::PreFix => "pre-fix",
32            Self::PostFix => "post-fix",
33        }
34    }
35
36    pub fn is_claude_event(&self) -> bool {
37        matches!(
38            self,
39            Self::PreToolUse
40                | Self::PostToolUse
41                | Self::UserPromptSubmit
42                | Self::Stop
43                | Self::PreCompact
44        )
45    }
46
47    pub fn is_uira_event(&self) -> bool {
48        matches!(
49            self,
50            Self::PreCheck
51                | Self::PostCheck
52                | Self::PreAi
53                | Self::PostAi
54                | Self::PreFix
55                | Self::PostFix
56        )
57    }
58}
59
60impl std::fmt::Display for HookEvent {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(f, "{}", self.as_str())
63    }
64}
65
66impl std::str::FromStr for HookEvent {
67    type Err = HookEventParseError;
68
69    fn from_str(s: &str) -> Result<Self, Self::Err> {
70        match s.to_lowercase().as_str() {
71            "pretooluse" | "pre-tool-use" | "pre_tool_use" => Ok(Self::PreToolUse),
72            "posttooluse" | "post-tool-use" | "post_tool_use" => Ok(Self::PostToolUse),
73            "userpromptsubmit" | "user-prompt-submit" | "user_prompt_submit" => {
74                Ok(Self::UserPromptSubmit)
75            }
76            "stop" => Ok(Self::Stop),
77            "precompact" | "pre-compact" | "pre_compact" => Ok(Self::PreCompact),
78            "precheck" | "pre-check" | "pre_check" => Ok(Self::PreCheck),
79            "postcheck" | "post-check" | "post_check" => Ok(Self::PostCheck),
80            "preai" | "pre-ai" | "pre_ai" => Ok(Self::PreAi),
81            "postai" | "post-ai" | "post_ai" => Ok(Self::PostAi),
82            "prefix" | "pre-fix" | "pre_fix" => Ok(Self::PreFix),
83            "postfix" | "post-fix" | "post_fix" => Ok(Self::PostFix),
84            _ => Err(HookEventParseError(s.to_string())),
85        }
86    }
87}
88
89#[derive(Debug, Clone)]
90pub struct HookEventParseError(pub String);
91
92impl std::fmt::Display for HookEventParseError {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        write!(f, "unknown hook event: {}", self.0)
95    }
96}
97
98impl std::error::Error for HookEventParseError {}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn test_event_as_str() {
106        assert_eq!(HookEvent::PreToolUse.as_str(), "PreToolUse");
107        assert_eq!(HookEvent::PreCheck.as_str(), "pre-check");
108    }
109
110    #[test]
111    fn test_event_parse() {
112        assert_eq!(
113            "PreToolUse".parse::<HookEvent>().unwrap(),
114            HookEvent::PreToolUse
115        );
116        assert_eq!(
117            "pre-check".parse::<HookEvent>().unwrap(),
118            HookEvent::PreCheck
119        );
120        assert!("invalid".parse::<HookEvent>().is_err());
121    }
122
123    #[test]
124    fn test_is_claude_event() {
125        assert!(HookEvent::PreToolUse.is_claude_event());
126        assert!(!HookEvent::PreCheck.is_claude_event());
127    }
128}