Skip to main content

ix_core/
entity.rs

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}