1#[allow(clippy::wildcard_imports)]
2use super::*;
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
14#[serde(try_from = "String", into = "String")]
15pub struct ProjectId(pub(super) String);
16
17impl StableId for ProjectId {
18 const PREFIX: &'static str = "p-";
19 const LABEL: &'static str = "project id";
20 const ARTICLE: &'static str = "a";
21
22 fn from_validated(raw: String) -> Self {
23 Self(raw)
24 }
25
26 fn as_str(&self) -> &str {
27 &self.0
28 }
29}
30
31impl ProjectId {
32 pub const MAX_LEN: usize = <Self as StableId>::MAX_LEN;
34
35 pub fn new(raw: &str) -> Result<Self> {
37 <Self as StableId>::new(raw)
38 }
39
40 #[must_use]
43 pub fn generate() -> Self {
44 <Self as StableId>::generate()
45 }
46
47 #[must_use]
49 pub fn as_str(&self) -> &str {
50 <Self as StableId>::as_str(self)
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
63#[serde(try_from = "String", into = "String")]
64pub struct EpicId(pub(super) String);
65
66impl StableId for EpicId {
67 const PREFIX: &'static str = "e-";
68 const LABEL: &'static str = "epic id";
69 const ARTICLE: &'static str = "an";
70
71 fn from_validated(raw: String) -> Self {
72 Self(raw)
73 }
74
75 fn as_str(&self) -> &str {
76 &self.0
77 }
78}
79
80impl EpicId {
81 pub const MAX_LEN: usize = <Self as StableId>::MAX_LEN;
83
84 pub fn new(raw: &str) -> Result<Self> {
86 <Self as StableId>::new(raw)
87 }
88
89 #[must_use]
92 pub fn generate() -> Self {
93 <Self as StableId>::generate()
94 }
95
96 #[must_use]
98 pub fn as_str(&self) -> &str {
99 <Self as StableId>::as_str(self)
100 }
101}
102
103impl std::fmt::Display for ProjectId {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 f.write_str(&self.0)
106 }
107}
108
109impl TryFrom<String> for ProjectId {
110 type Error = TixError;
111
112 fn try_from(raw: String) -> Result<Self> {
113 Self::new(&raw)
114 }
115}
116
117impl std::fmt::Display for EpicId {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 f.write_str(&self.0)
120 }
121}
122
123impl TryFrom<String> for EpicId {
124 type Error = TixError;
125
126 fn try_from(raw: String) -> Result<Self> {
127 Self::new(&raw)
128 }
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
140#[serde(try_from = "String", into = "String")]
141pub struct InitiativeId(pub(super) String);
142
143impl StableId for InitiativeId {
144 const PREFIX: &'static str = "i-";
145 const LABEL: &'static str = "initiative id";
146 const ARTICLE: &'static str = "an";
147
148 fn from_validated(raw: String) -> Self {
149 Self(raw)
150 }
151
152 fn as_str(&self) -> &str {
153 &self.0
154 }
155}
156
157impl InitiativeId {
158 pub const MAX_LEN: usize = <Self as StableId>::MAX_LEN;
160
161 pub fn new(raw: &str) -> Result<Self> {
163 <Self as StableId>::new(raw)
164 }
165
166 #[must_use]
169 pub fn generate() -> Self {
170 <Self as StableId>::generate()
171 }
172
173 #[must_use]
175 pub fn as_str(&self) -> &str {
176 <Self as StableId>::as_str(self)
177 }
178}
179
180impl std::fmt::Display for InitiativeId {
181 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182 f.write_str(&self.0)
183 }
184}
185
186impl TryFrom<String> for InitiativeId {
187 type Error = TixError;
188
189 fn try_from(raw: String) -> Result<Self> {
190 Self::new(&raw)
191 }
192}
193
194pub(super) fn is_structural_key_char(c: char) -> bool {
197 c.is_whitespace()
198 || matches!(c, '.' | '"' | '\'' | '[' | ']' | '#' | '=' | '\\')
199 || c.is_control()
200}