1use crate::{
8 component::{
9 IcalComponentKind, available, daylight, participant, standard, valarm, vavailability,
10 vcalendar, vevent, vfreebusy, vjournal, vlocation, vresource, vtimezone, vtodo,
11 },
12 prop::IcalPropKind,
13};
14
15pub trait IcalComponentSpec {
20 const KIND: IcalComponentKind;
22
23 fn allowed_children() -> &'static [IcalComponentKind] {
25 &[]
26 }
27
28 fn required_props() -> &'static [IcalPropKind] {
30 &[]
31 }
32}
33
34#[allow(dead_code)]
37pub(crate) struct IcalComponentSpecFns {
38 pub kind: IcalComponentKind,
41 pub allowed_children: fn() -> &'static [IcalComponentKind],
43 pub required_props: fn() -> &'static [IcalPropKind],
45}
46
47fn spec_fns<C: IcalComponentSpec>() -> IcalComponentSpecFns {
49 IcalComponentSpecFns {
50 kind: C::KIND,
51 allowed_children: C::allowed_children,
52 required_props: C::required_props,
53 }
54}
55
56pub(crate) fn component_spec(component: IcalComponentKind) -> IcalComponentSpecFns {
58 use IcalComponentKind::*;
59
60 match component {
61 VCalendar => spec_fns::<vcalendar::VCALENDAR>(),
62 VEvent => spec_fns::<vevent::VEVENT>(),
63 VTodo => spec_fns::<vtodo::VTODO>(),
64 VJournal => spec_fns::<vjournal::VJOURNAL>(),
65 VFreeBusy => spec_fns::<vfreebusy::VFREEBUSY>(),
66 VTimezone => spec_fns::<vtimezone::VTIMEZONE>(),
67 Standard => spec_fns::<standard::STANDARD>(),
68 Daylight => spec_fns::<daylight::DAYLIGHT>(),
69 VAlarm => spec_fns::<valarm::VALARM>(),
70 Participant => spec_fns::<participant::PARTICIPANT>(),
71 VLocation => spec_fns::<vlocation::VLOCATION>(),
72 VResource => spec_fns::<vresource::VRESOURCE>(),
73 VAvailability => spec_fns::<vavailability::VAVAILABILITY>(),
74 Available => spec_fns::<available::AVAILABLE>(),
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use alloc::vec::Vec;
81
82 use crate::component::{IcalComponentKind, spec::component_spec};
83
84 #[test]
85 fn dispatches_every_component_onto_its_own_marker() {
86 for kind in IcalComponentKind::ALL {
87 assert_eq!(component_spec(kind).kind, kind, "{}", &*kind);
88 }
89 }
90
91 #[test]
92 fn no_component_requires_one_property_twice() {
93 for kind in IcalComponentKind::ALL {
94 let spec = component_spec(kind);
95
96 let mut required: Vec<&str> = (spec.required_props)().iter().map(|p| &**p).collect();
97 let count = required.len();
98 required.sort_unstable();
99 required.dedup();
100
101 assert_eq!(
102 required.len(),
103 count,
104 "{} requires a property twice",
105 &*kind
106 );
107 }
108 }
109}