1use core::{error, fmt, ops, str};
14
15use alloc::{
16 borrow::Cow,
17 string::{String, ToString},
18 vec::Vec,
19};
20
21use crate::value::owned;
22
23#[derive(Debug)]
25pub struct ParseIcalParamKindError(
26 String,
28);
29
30impl fmt::Display for ParseIcalParamKindError {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 write!(f, "Cannot parse iCalendar parameter `{}`", self.0)
33 }
34}
35
36impl error::Error for ParseIcalParamKindError {}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq)]
42pub enum IcalParamKind {
43 AltRep,
45 Cn,
47 CuType,
49 DelegatedFrom,
51 DelegatedTo,
53 Dir,
55 Encoding,
57 FmtType,
59 FbType,
61 Language,
63 Member,
65 PartStat,
67 Range,
69 Related,
71 RelType,
73 Role,
75 Rsvp,
77 SentBy,
79 TzId,
81 Value,
83 Display,
85 Email,
87 Feature,
89 Label,
91 Order,
93 Schema,
95 Derived,
97 ScheduleAgent,
100 ScheduleForceSend,
103 ScheduleStatus,
105 LinkRel,
107 Gap,
109 Charset,
111}
112
113impl IcalParamKind {
114 pub const ALL: [Self; 33] = [
118 Self::AltRep,
119 Self::Cn,
120 Self::CuType,
121 Self::DelegatedFrom,
122 Self::DelegatedTo,
123 Self::Dir,
124 Self::Encoding,
125 Self::FmtType,
126 Self::FbType,
127 Self::Language,
128 Self::Member,
129 Self::PartStat,
130 Self::Range,
131 Self::Related,
132 Self::RelType,
133 Self::Role,
134 Self::Rsvp,
135 Self::SentBy,
136 Self::TzId,
137 Self::Value,
138 Self::Display,
139 Self::Email,
140 Self::Feature,
141 Self::Label,
142 Self::Order,
143 Self::Schema,
144 Self::Derived,
145 Self::ScheduleAgent,
146 Self::ScheduleForceSend,
147 Self::ScheduleStatus,
148 Self::LinkRel,
149 Self::Gap,
150 Self::Charset,
151 ];
152}
153
154impl str::FromStr for IcalParamKind {
155 type Err = ParseIcalParamKindError;
156
157 fn from_str(kind: &str) -> Result<Self, Self::Err> {
159 let kind = match kind {
160 kind if kind.eq_ignore_ascii_case("ALTREP") => Self::AltRep,
161 kind if kind.eq_ignore_ascii_case("CN") => Self::Cn,
162 kind if kind.eq_ignore_ascii_case("CUTYPE") => Self::CuType,
163 kind if kind.eq_ignore_ascii_case("DELEGATED-FROM") => Self::DelegatedFrom,
164 kind if kind.eq_ignore_ascii_case("DELEGATED-TO") => Self::DelegatedTo,
165 kind if kind.eq_ignore_ascii_case("DIR") => Self::Dir,
166 kind if kind.eq_ignore_ascii_case("ENCODING") => Self::Encoding,
167 kind if kind.eq_ignore_ascii_case("FMTTYPE") => Self::FmtType,
168 kind if kind.eq_ignore_ascii_case("FBTYPE") => Self::FbType,
169 kind if kind.eq_ignore_ascii_case("LANGUAGE") => Self::Language,
170 kind if kind.eq_ignore_ascii_case("MEMBER") => Self::Member,
171 kind if kind.eq_ignore_ascii_case("PARTSTAT") => Self::PartStat,
172 kind if kind.eq_ignore_ascii_case("RANGE") => Self::Range,
173 kind if kind.eq_ignore_ascii_case("RELATED") => Self::Related,
174 kind if kind.eq_ignore_ascii_case("RELTYPE") => Self::RelType,
175 kind if kind.eq_ignore_ascii_case("ROLE") => Self::Role,
176 kind if kind.eq_ignore_ascii_case("RSVP") => Self::Rsvp,
177 kind if kind.eq_ignore_ascii_case("SENT-BY") => Self::SentBy,
178 kind if kind.eq_ignore_ascii_case("TZID") => Self::TzId,
179 kind if kind.eq_ignore_ascii_case("VALUE") => Self::Value,
180 kind if kind.eq_ignore_ascii_case("DISPLAY") => Self::Display,
181 kind if kind.eq_ignore_ascii_case("EMAIL") => Self::Email,
182 kind if kind.eq_ignore_ascii_case("FEATURE") => Self::Feature,
183 kind if kind.eq_ignore_ascii_case("LABEL") => Self::Label,
184 kind if kind.eq_ignore_ascii_case("ORDER") => Self::Order,
185 kind if kind.eq_ignore_ascii_case("SCHEMA") => Self::Schema,
186 kind if kind.eq_ignore_ascii_case("DERIVED") => Self::Derived,
187 kind if kind.eq_ignore_ascii_case("SCHEDULE-AGENT") => Self::ScheduleAgent,
188 kind if kind.eq_ignore_ascii_case("SCHEDULE-FORCE-SEND") => Self::ScheduleForceSend,
189 kind if kind.eq_ignore_ascii_case("SCHEDULE-STATUS") => Self::ScheduleStatus,
190 kind if kind.eq_ignore_ascii_case("LINKREL") => Self::LinkRel,
191 kind if kind.eq_ignore_ascii_case("GAP") => Self::Gap,
192 kind if kind.eq_ignore_ascii_case("CHARSET") => Self::Charset,
193 _ => return Err(ParseIcalParamKindError(kind.to_string())),
194 };
195
196 Ok(kind)
197 }
198}
199
200impl ops::Deref for IcalParamKind {
201 type Target = str;
202
203 fn deref(&self) -> &Self::Target {
204 match self {
205 Self::AltRep => "ALTREP",
206 Self::Cn => "CN",
207 Self::CuType => "CUTYPE",
208 Self::DelegatedFrom => "DELEGATED-FROM",
209 Self::DelegatedTo => "DELEGATED-TO",
210 Self::Dir => "DIR",
211 Self::Encoding => "ENCODING",
212 Self::FmtType => "FMTTYPE",
213 Self::FbType => "FBTYPE",
214 Self::Language => "LANGUAGE",
215 Self::Member => "MEMBER",
216 Self::PartStat => "PARTSTAT",
217 Self::Range => "RANGE",
218 Self::Related => "RELATED",
219 Self::RelType => "RELTYPE",
220 Self::Role => "ROLE",
221 Self::Rsvp => "RSVP",
222 Self::SentBy => "SENT-BY",
223 Self::TzId => "TZID",
224 Self::Value => "VALUE",
225 Self::Display => "DISPLAY",
226 Self::Email => "EMAIL",
227 Self::Feature => "FEATURE",
228 Self::Label => "LABEL",
229 Self::Order => "ORDER",
230 Self::Schema => "SCHEMA",
231 Self::Derived => "DERIVED",
232 Self::ScheduleAgent => "SCHEDULE-AGENT",
233 Self::ScheduleForceSend => "SCHEDULE-FORCE-SEND",
234 Self::ScheduleStatus => "SCHEDULE-STATUS",
235 Self::LinkRel => "LINKREL",
236 Self::Gap => "GAP",
237 Self::Charset => "CHARSET",
238 }
239 }
240}
241
242#[derive(Clone, Debug, PartialEq, Eq)]
246pub enum IcalParam<'a> {
247 AltRep(Cow<'a, str>),
249 Cn(Cow<'a, str>),
251 CuType(Cow<'a, str>),
253 DelegatedFrom(Vec<Cow<'a, str>>),
255 DelegatedTo(Vec<Cow<'a, str>>),
257 Dir(Cow<'a, str>),
259 Encoding(Cow<'a, str>),
261 FmtType(Cow<'a, str>),
263 FbType(Cow<'a, str>),
265 Language(Cow<'a, str>),
267 Member(Vec<Cow<'a, str>>),
269 PartStat(Cow<'a, str>),
271 Range(Cow<'a, str>),
273 Related(Cow<'a, str>),
275 RelType(Cow<'a, str>),
277 Role(Cow<'a, str>),
279 Rsvp(Cow<'a, str>),
281 SentBy(Cow<'a, str>),
283 TzId(Cow<'a, str>),
285 Value(Cow<'a, str>),
287 Display(Cow<'a, str>),
289 Email(Cow<'a, str>),
291 Feature(Vec<Cow<'a, str>>),
293 Label(Cow<'a, str>),
295 Order(Cow<'a, str>),
297 Schema(Cow<'a, str>),
299 Derived(Cow<'a, str>),
301 ScheduleAgent(Cow<'a, str>),
303 ScheduleForceSend(Cow<'a, str>),
305 ScheduleStatus(Cow<'a, str>),
307 LinkRel(Cow<'a, str>),
309 Gap(Cow<'a, str>),
311 Charset(Cow<'a, str>),
313
314 Unknown {
316 name: Cow<'a, str>,
318 values: Vec<Cow<'a, str>>,
320 },
321}
322
323impl IcalParam<'_> {
324 pub fn kind(&self) -> Option<IcalParamKind> {
327 match self {
328 Self::AltRep(_) => Some(IcalParamKind::AltRep),
329 Self::Cn(_) => Some(IcalParamKind::Cn),
330 Self::CuType(_) => Some(IcalParamKind::CuType),
331 Self::DelegatedFrom(_) => Some(IcalParamKind::DelegatedFrom),
332 Self::DelegatedTo(_) => Some(IcalParamKind::DelegatedTo),
333 Self::Dir(_) => Some(IcalParamKind::Dir),
334 Self::Encoding(_) => Some(IcalParamKind::Encoding),
335 Self::FmtType(_) => Some(IcalParamKind::FmtType),
336 Self::FbType(_) => Some(IcalParamKind::FbType),
337 Self::Language(_) => Some(IcalParamKind::Language),
338 Self::Member(_) => Some(IcalParamKind::Member),
339 Self::PartStat(_) => Some(IcalParamKind::PartStat),
340 Self::Range(_) => Some(IcalParamKind::Range),
341 Self::Related(_) => Some(IcalParamKind::Related),
342 Self::RelType(_) => Some(IcalParamKind::RelType),
343 Self::Role(_) => Some(IcalParamKind::Role),
344 Self::Rsvp(_) => Some(IcalParamKind::Rsvp),
345 Self::SentBy(_) => Some(IcalParamKind::SentBy),
346 Self::TzId(_) => Some(IcalParamKind::TzId),
347 Self::Value(_) => Some(IcalParamKind::Value),
348 Self::Display(_) => Some(IcalParamKind::Display),
349 Self::Email(_) => Some(IcalParamKind::Email),
350 Self::Feature(_) => Some(IcalParamKind::Feature),
351 Self::Label(_) => Some(IcalParamKind::Label),
352 Self::Order(_) => Some(IcalParamKind::Order),
353 Self::Schema(_) => Some(IcalParamKind::Schema),
354 Self::Derived(_) => Some(IcalParamKind::Derived),
355 Self::ScheduleAgent(_) => Some(IcalParamKind::ScheduleAgent),
356 Self::ScheduleForceSend(_) => Some(IcalParamKind::ScheduleForceSend),
357 Self::ScheduleStatus(_) => Some(IcalParamKind::ScheduleStatus),
358 Self::LinkRel(_) => Some(IcalParamKind::LinkRel),
359 Self::Gap(_) => Some(IcalParamKind::Gap),
360 Self::Charset(_) => Some(IcalParamKind::Charset),
361 Self::Unknown { .. } => None,
362 }
363 }
364
365 pub fn into_owned(self) -> IcalParam<'static> {
369 use IcalParam::*;
370
371 match self {
372 AltRep(value) => AltRep(owned(value)),
373 Cn(value) => Cn(owned(value)),
374 CuType(value) => CuType(owned(value)),
375 DelegatedFrom(values) => DelegatedFrom(values.into_iter().map(owned).collect()),
376 DelegatedTo(values) => DelegatedTo(values.into_iter().map(owned).collect()),
377 Dir(value) => Dir(owned(value)),
378 Encoding(value) => Encoding(owned(value)),
379 FmtType(value) => FmtType(owned(value)),
380 FbType(value) => FbType(owned(value)),
381 Language(value) => Language(owned(value)),
382 Member(values) => Member(values.into_iter().map(owned).collect()),
383 PartStat(value) => PartStat(owned(value)),
384 Range(value) => Range(owned(value)),
385 Related(value) => Related(owned(value)),
386 RelType(value) => RelType(owned(value)),
387 Role(value) => Role(owned(value)),
388 Rsvp(value) => Rsvp(owned(value)),
389 SentBy(value) => SentBy(owned(value)),
390 TzId(value) => TzId(owned(value)),
391 Value(value) => Value(owned(value)),
392 Display(value) => Display(owned(value)),
393 Email(value) => Email(owned(value)),
394 Feature(values) => Feature(values.into_iter().map(owned).collect()),
395 Label(value) => Label(owned(value)),
396 Order(value) => Order(owned(value)),
397 Schema(value) => Schema(owned(value)),
398 Derived(value) => Derived(owned(value)),
399 ScheduleAgent(value) => ScheduleAgent(owned(value)),
400 ScheduleForceSend(value) => ScheduleForceSend(owned(value)),
401 ScheduleStatus(value) => ScheduleStatus(owned(value)),
402 LinkRel(value) => LinkRel(owned(value)),
403 Gap(value) => Gap(owned(value)),
404 Charset(value) => Charset(owned(value)),
405 Unknown { name, values } => Unknown {
406 name: owned(name),
407 values: values.into_iter().map(owned).collect(),
408 },
409 }
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use core::str::FromStr;
416
417 use crate::param::IcalParamKind;
418
419 #[test]
420 fn round_trips_every_kind_through_its_wire_name() {
421 for kind in [
422 IcalParamKind::Role,
423 IcalParamKind::DelegatedFrom,
424 IcalParamKind::TzId,
425 ] {
426 assert_eq!(IcalParamKind::from_str(&kind).ok(), Some(kind));
427 }
428 assert_eq!(
431 IcalParamKind::from_str("role").ok(),
432 Some(IcalParamKind::Role),
433 );
434 assert!(IcalParamKind::from_str("X-CUSTOM").is_err());
435 }
436}