1use std::convert::TryFrom;
17
18use crate::keyword::{
19 KW_CALSCALE_GREGORIAN, KW_METHOD_ADD, KW_METHOD_CANCEL, KW_METHOD_COUNTER,
20 KW_METHOD_DECLINECOUNTER, KW_METHOD_PUBLISH, KW_METHOD_REFRESH, KW_METHOD_REPLY,
21 KW_METHOD_REQUEST, KW_VERSION_2_0,
22};
23use crate::parameter::Parameter;
24use crate::property::PropertyKind;
25use crate::property::common::take_single_text;
26use crate::string_storage::{Segments, StringStorage};
27use crate::syntax::RawParameter;
28use crate::typed::{ParsedProperty, TypedError};
29use crate::value::ValueText;
30
31define_prop_value_enum! {
32 #[derive(Default)]
34 pub enum CalendarScaleValue {
35 #[default]
37 Gregorian => KW_CALSCALE_GREGORIAN
38 }
39}
40
41#[derive(Debug, Clone, Default)]
43pub struct CalendarScale<S: StringStorage> {
44 pub value: CalendarScaleValue,
46 pub x_parameters: Vec<RawParameter<S>>,
48 pub retained_parameters: Vec<Parameter<S>>,
50 pub span: S::Span,
52}
53
54impl<'src> TryFrom<ParsedProperty<'src>> for CalendarScale<Segments<'src>> {
55 type Error = Vec<TypedError<'src>>;
56
57 fn try_from(prop: ParsedProperty<'src>) -> Result<Self, Self::Error> {
58 if !matches!(prop.kind, PropertyKind::CalScale) {
59 return Err(vec![TypedError::PropertyUnexpectedKind {
60 expected: PropertyKind::CalScale,
61 found: prop.kind,
62 span: prop.span,
63 }]);
64 }
65
66 let mut x_parameters = Vec::new();
67 let mut retained_parameters = Vec::new();
68
69 for param in prop.parameters {
70 match param {
71 Parameter::XName(raw) => x_parameters.push(raw),
72 p @ Parameter::Unrecognized { .. } => retained_parameters.push(p),
73 p => {
74 retained_parameters.push(p);
76 }
77 }
78 }
79
80 let value_span = prop.value.span();
81 let text = take_single_text(&PropertyKind::CalScale, prop.value)?;
82 let value = text.try_into().map_err(|text| {
83 vec![TypedError::PropertyInvalidValue {
84 property: PropertyKind::CalScale,
85 value: format!("Unsupported calendar scale: {text}"),
86 span: value_span,
87 }]
88 })?;
89
90 Ok(CalendarScale {
91 value,
92 x_parameters,
93 retained_parameters,
94 span: prop.span,
95 })
96 }
97}
98
99impl CalendarScale<Segments<'_>> {
100 #[must_use]
102 pub fn to_owned(&self) -> CalendarScale<String> {
103 CalendarScale {
104 value: self.value,
105 x_parameters: self
106 .x_parameters
107 .iter()
108 .map(RawParameter::to_owned)
109 .collect(),
110 retained_parameters: self
111 .retained_parameters
112 .iter()
113 .map(Parameter::to_owned)
114 .collect(),
115 span: (),
116 }
117 }
118}
119
120define_prop_value_enum! {
121 #[derive(Default)]
123 pub enum MethodValue {
124 #[default]
126 Publish => KW_METHOD_PUBLISH,
127 Request => KW_METHOD_REQUEST,
129 Reply => KW_METHOD_REPLY,
131 Add => KW_METHOD_ADD,
133 Cancel => KW_METHOD_CANCEL,
135 Refresh => KW_METHOD_REFRESH,
137 Counter => KW_METHOD_COUNTER,
139 DeclineCounter => KW_METHOD_DECLINECOUNTER,
141 }
142}
143
144#[derive(Debug, Clone, Default)]
146pub struct Method<S: StringStorage> {
147 pub value: MethodValue,
149 pub x_parameters: Vec<RawParameter<S>>,
151 pub retained_parameters: Vec<Parameter<S>>,
153 pub span: S::Span,
155}
156
157impl<'src> TryFrom<ParsedProperty<'src>> for Method<Segments<'src>> {
158 type Error = Vec<TypedError<'src>>;
159
160 fn try_from(prop: ParsedProperty<'src>) -> Result<Self, Self::Error> {
161 if !matches!(prop.kind, PropertyKind::Method) {
162 return Err(vec![TypedError::PropertyUnexpectedKind {
163 expected: PropertyKind::Method,
164 found: prop.kind,
165 span: prop.span,
166 }]);
167 }
168
169 let mut x_parameters = Vec::new();
170 let mut retained_parameters = Vec::new();
171
172 for param in prop.parameters {
173 match param {
174 Parameter::XName(raw) => x_parameters.push(raw),
175 p @ Parameter::Unrecognized { .. } => retained_parameters.push(p),
176 p => {
177 retained_parameters.push(p);
179 }
180 }
181 }
182
183 let value_span = prop.value.span();
184 let text = take_single_text(&PropertyKind::Method, prop.value)?;
185 let value = text.try_into().map_err(|text| {
186 vec![TypedError::PropertyInvalidValue {
187 property: PropertyKind::Method,
188 value: format!("Unsupported method type: {text}"),
189 span: value_span,
190 }]
191 })?;
192
193 Ok(Method {
194 value,
195 x_parameters,
196 retained_parameters,
197 span: prop.span,
198 })
199 }
200}
201
202impl Method<Segments<'_>> {
203 #[must_use]
205 pub fn to_owned(&self) -> Method<String> {
206 Method {
207 value: self.value,
208 x_parameters: self
209 .x_parameters
210 .iter()
211 .map(RawParameter::to_owned)
212 .collect(),
213 retained_parameters: self
214 .retained_parameters
215 .iter()
216 .map(Parameter::to_owned)
217 .collect(),
218 span: (),
219 }
220 }
221}
222
223#[derive(Debug, Clone, Default)]
225pub struct ProductId<S: StringStorage> {
226 pub value: ValueText<S>,
230 pub x_parameters: Vec<RawParameter<S>>,
232 pub retained_parameters: Vec<Parameter<S>>,
234 pub span: S::Span,
236}
237
238impl<'src> TryFrom<ParsedProperty<'src>> for ProductId<Segments<'src>> {
239 type Error = Vec<TypedError<'src>>;
240
241 fn try_from(prop: ParsedProperty<'src>) -> Result<Self, Self::Error> {
242 if !matches!(prop.kind, PropertyKind::ProdId) {
243 return Err(vec![TypedError::PropertyUnexpectedKind {
244 expected: PropertyKind::ProdId,
245 found: prop.kind,
246 span: prop.span,
247 }]);
248 }
249
250 let mut x_parameters = Vec::new();
251 let mut retained_parameters = Vec::new();
252 for param in prop.parameters {
253 match param {
254 Parameter::XName(raw) => x_parameters.push(raw),
255 p @ Parameter::Unrecognized { .. } => retained_parameters.push(p),
256 p => {
257 retained_parameters.push(p);
259 }
260 }
261 }
262
263 let value = take_single_text(&PropertyKind::ProdId, prop.value)?;
264 Ok(ProductId {
265 value,
266 x_parameters,
267 retained_parameters,
268 span: prop.span,
269 })
270 }
271}
272
273impl ProductId<Segments<'_>> {
274 #[must_use]
276 pub fn to_owned(&self) -> ProductId<String> {
277 ProductId {
278 value: self.value.to_owned(),
279 x_parameters: self
280 .x_parameters
281 .iter()
282 .map(RawParameter::to_owned)
283 .collect(),
284 retained_parameters: self
285 .retained_parameters
286 .iter()
287 .map(Parameter::to_owned)
288 .collect(),
289 span: (),
290 }
291 }
292}
293
294define_prop_value_enum! {
295 #[derive(Default)]
297 pub enum VersionValue {
298 #[default]
300 V2_0 => KW_VERSION_2_0,
301 }
302}
303
304#[derive(Debug, Clone, Default)]
306pub struct Version<S: StringStorage> {
307 pub value: VersionValue,
309 pub x_parameters: Vec<RawParameter<S>>,
311 pub retained_parameters: Vec<Parameter<S>>,
313 pub span: S::Span,
315}
316
317impl<'src> TryFrom<ParsedProperty<'src>> for Version<Segments<'src>> {
318 type Error = Vec<TypedError<'src>>;
319
320 fn try_from(prop: ParsedProperty<'src>) -> Result<Self, Self::Error> {
321 if !matches!(prop.kind, PropertyKind::Version) {
322 return Err(vec![TypedError::PropertyUnexpectedKind {
323 expected: PropertyKind::Version,
324 found: prop.kind,
325 span: prop.span,
326 }]);
327 }
328
329 let mut x_parameters = Vec::new();
330 let mut retained_parameters = Vec::new();
331
332 for param in prop.parameters {
333 match param {
334 Parameter::XName(raw) => x_parameters.push(raw),
335 p @ Parameter::Unrecognized { .. } => retained_parameters.push(p),
336 p => {
337 retained_parameters.push(p);
339 }
340 }
341 }
342
343 let value_span = prop.value.span();
344 let text = take_single_text(&PropertyKind::Version, prop.value)?;
345 let value = text.try_into().map_err(|text| {
346 vec![TypedError::PropertyInvalidValue {
347 property: PropertyKind::Version,
348 value: format!("Unsupported iCalendar version: {text}"),
349 span: value_span,
350 }]
351 })?;
352
353 Ok(Version {
354 value,
355 x_parameters,
356 retained_parameters,
357 span: prop.span,
358 })
359 }
360}
361
362impl Version<Segments<'_>> {
363 #[must_use]
365 pub fn to_owned(&self) -> Version<String> {
366 Version {
367 value: self.value,
368 x_parameters: self
369 .x_parameters
370 .iter()
371 .map(RawParameter::to_owned)
372 .collect(),
373 retained_parameters: self
374 .retained_parameters
375 .iter()
376 .map(Parameter::to_owned)
377 .collect(),
378 span: (),
379 }
380 }
381}