1use std::str::FromStr;
2
3use thiserror::Error;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub enum EntityKind {
7 Decision,
8 Issue,
9 Idea,
10 Report,
11 Source,
12 Citation,
13 Agent,
14 Session,
15}
16
17impl EntityKind {
18 #[must_use]
19 pub const fn as_str(self) -> &'static str {
20 match self {
21 Self::Decision => "decision",
22 Self::Issue => "issue",
23 Self::Idea => "idea",
24 Self::Report => "report",
25 Self::Source => "source",
26 Self::Citation => "citation",
27 Self::Agent => "agent",
28 Self::Session => "session",
29 }
30 }
31
32 #[must_use]
33 pub const fn directory_name(self) -> &'static str {
34 match self {
35 Self::Decision => "decisions",
36 Self::Issue => "issues",
37 Self::Idea => "ideas",
38 Self::Report => "reports",
39 Self::Source => "sources",
40 Self::Citation => "citations",
41 Self::Agent => "agents",
42 Self::Session => "sessions",
43 }
44 }
45
46 #[must_use]
47 pub const fn id_prefix(self) -> &'static str {
48 match self {
49 Self::Decision => "dec",
50 Self::Issue => "iss",
51 Self::Idea => "idea",
52 Self::Report => "rpt",
53 Self::Source => "src",
54 Self::Citation => "cite",
55 Self::Agent => "agt",
56 Self::Session => "ses",
57 }
58 }
59}
60
61#[derive(Debug, Error)]
62pub enum ParseEntityKindError {
63 #[error("Unknown entity kind: {0}")]
64 UnknownKind(String),
65}
66
67impl FromStr for EntityKind {
68 type Err = ParseEntityKindError;
69
70 fn from_str(s: &str) -> Result<Self, Self::Err> {
71 let normalized = s.trim().to_ascii_lowercase();
72 match normalized.as_str() {
73 "decision" | "decisions" => Ok(Self::Decision),
74 "issue" | "issues" => Ok(Self::Issue),
75 "idea" | "ideas" => Ok(Self::Idea),
76 "report" | "reports" => Ok(Self::Report),
77 "source" | "sources" => Ok(Self::Source),
78 "citation" | "citations" => Ok(Self::Citation),
79 "agent" | "agents" => Ok(Self::Agent),
80 "session" | "sessions" => Ok(Self::Session),
81 _ => Err(ParseEntityKindError::UnknownKind(s.to_string())),
82 }
83 }
84}
85
86#[must_use]
87pub fn kind_from_id(id: &str) -> Option<EntityKind> {
88 let (prefix, _) = id.split_once('-')?;
89 match prefix {
90 "dec" => Some(EntityKind::Decision),
91 "iss" | "bd" => Some(EntityKind::Issue),
92 "idea" => Some(EntityKind::Idea),
93 "rpt" => Some(EntityKind::Report),
94 "src" => Some(EntityKind::Source),
95 "cite" => Some(EntityKind::Citation),
96 "agt" => Some(EntityKind::Agent),
97 "ses" => Some(EntityKind::Session),
98 _ => None,
99 }
100}
101
102#[must_use]
103pub fn looks_like_entity_id(id: &str) -> bool {
104 ix_id::parse_id(id).is_ok()
105}