1use std::convert::TryFrom;
11
12use crate::parameter::{Parameter, ValueType};
13use crate::property::PropertyKind;
14use crate::string_storage::{Segments, StringStorage};
15use crate::syntax::RawParameter;
16use crate::typed::{ParsedProperty, TypedError};
17use crate::value::{Value, ValueText};
18
19pub fn take_single_value<'src>(
21 kind: &PropertyKind<Segments<'src>>,
22 value: Value<Segments<'src>>,
23) -> Result<Value<Segments<'src>>, Vec<TypedError<'src>>> {
24 if !value.len() == 1 {
25 return Err(vec![TypedError::PropertyInvalidValueCount {
26 property: kind.clone(),
27 expected: 1,
28 found: value.len(),
29 span: value.span(),
30 }]);
31 }
32
33 Ok(value)
34}
35
36pub fn take_single_cal_address<'src>(
38 kind: &PropertyKind<Segments<'src>>,
39 value: Value<Segments<'src>>,
40) -> Result<Segments<'src>, Vec<TypedError<'src>>> {
41 const EXPECTED: &[ValueType<String>] = &[ValueType::CalendarUserAddress];
42 let value = take_single_value(kind, value)?;
43 match value {
44 Value::CalAddress { value, .. } => Ok(value),
45 v => Err(vec![TypedError::PropertyUnexpectedValue {
46 property: kind.clone(),
47 expected: EXPECTED,
48 found: v.kind().into(),
49 span: v.span(),
50 }]),
51 }
52}
53
54pub fn take_single_uri<'src>(
56 kind: &PropertyKind<Segments<'src>>,
57 value: Value<Segments<'src>>,
58) -> Result<Segments<'src>, Vec<TypedError<'src>>> {
59 const EXPECTED: &[ValueType<String>] = &[ValueType::Uri];
60 let value = take_single_value(kind, value)?;
61 match value {
62 Value::Uri { value, .. } => Ok(value),
63 v => Err(vec![TypedError::PropertyUnexpectedValue {
64 property: kind.clone(),
65 expected: EXPECTED,
66 found: v.kind().into(),
67 span: v.span(),
68 }]),
69 }
70}
71
72pub fn take_single_text<'src>(
74 kind: &PropertyKind<Segments<'src>>,
75 value: Value<Segments<'src>>,
76) -> Result<ValueText<Segments<'src>>, Vec<TypedError<'src>>> {
77 const EXPECTED: &[ValueType<String>] = &[ValueType::Text];
78 let value = take_single_value(kind, value)?;
79
80 match value {
81 Value::Text { mut values, .. } if values.len() == 1 => Ok(values.pop().unwrap()),
82 Value::Text { ref values, .. } => {
83 let span = value.span();
84 Err(vec![TypedError::PropertyInvalidValueCount {
85 property: kind.clone(),
86 expected: 1,
87 found: values.len(),
88 span,
89 }])
90 }
91 v => {
92 let span = v.span();
93 Err(vec![TypedError::PropertyUnexpectedValue {
94 property: kind.clone(),
95 expected: EXPECTED,
96 found: v.kind().into(),
97 span,
98 }])
99 }
100 }
101}
102
103#[derive(Debug, Clone)]
109pub struct UriProperty<S: StringStorage> {
110 pub uri: S,
112 pub x_parameters: Vec<RawParameter<S>>,
114 pub retained_parameters: Vec<Parameter<S>>,
116}
117
118impl<'src> TryFrom<ParsedProperty<'src>> for UriProperty<Segments<'src>> {
119 type Error = Vec<TypedError<'src>>;
120
121 fn try_from(prop: ParsedProperty<'src>) -> Result<Self, Self::Error> {
122 let mut x_parameters = Vec::new();
123 let mut retained_parameters = Vec::new();
124
125 for param in prop.parameters {
126 match param {
127 Parameter::XName(raw) => x_parameters.push(raw),
128 p @ Parameter::Unrecognized { .. } => retained_parameters.push(p),
129 p => {
130 retained_parameters.push(p);
132 }
133 }
134 }
135
136 let uri = take_single_uri(&prop.kind, prop.value)?;
137
138 Ok(UriProperty {
139 uri,
140 x_parameters,
141 retained_parameters,
142 })
143 }
144}
145
146impl UriProperty<Segments<'_>> {
147 #[must_use]
149 pub fn to_owned(&self) -> UriProperty<String> {
150 UriProperty {
151 uri: self.uri.to_owned(),
152 x_parameters: self
153 .x_parameters
154 .iter()
155 .map(RawParameter::to_owned)
156 .collect(),
157 retained_parameters: self
158 .retained_parameters
159 .iter()
160 .map(Parameter::to_owned)
161 .collect(),
162 }
163 }
164}
165
166#[derive(Debug, Clone)]
176pub struct TextOnly<S: StringStorage> {
177 pub content: ValueText<S>,
179 pub x_parameters: Vec<RawParameter<S>>,
181 pub retained_parameters: Vec<Parameter<S>>,
183}
184
185impl<'src> TryFrom<ParsedProperty<'src>> for TextOnly<Segments<'src>> {
186 type Error = Vec<TypedError<'src>>;
187
188 fn try_from(prop: ParsedProperty<'src>) -> Result<Self, Self::Error> {
189 let content = take_single_text(&prop.kind, prop.value)?;
190
191 let mut x_parameters = Vec::new();
192 let mut retained_parameters = Vec::new();
193
194 for param in prop.parameters {
195 match param {
196 Parameter::XName(raw) => x_parameters.push(raw),
197 p @ Parameter::Unrecognized { .. } => retained_parameters.push(p),
198 p => {
199 retained_parameters.push(p);
201 }
202 }
203 }
204
205 Ok(Self {
206 content,
207 x_parameters,
208 retained_parameters,
209 })
210 }
211}
212
213impl TextOnly<Segments<'_>> {
214 #[must_use]
216 pub fn to_owned(&self) -> TextOnly<String> {
217 TextOnly {
218 content: self.content.to_owned(),
219 x_parameters: self
220 .x_parameters
221 .iter()
222 .map(RawParameter::to_owned)
223 .collect(),
224 retained_parameters: self
225 .retained_parameters
226 .iter()
227 .map(Parameter::to_owned)
228 .collect(),
229 }
230 }
231}
232
233#[derive(Debug, Clone)]
243pub struct TextWithLanguage<S: StringStorage> {
244 pub content: ValueText<S>,
246
247 pub language: Option<S>,
249
250 pub x_parameters: Vec<RawParameter<S>>,
252
253 pub retained_parameters: Vec<Parameter<S>>,
255}
256
257impl<'src> TryFrom<ParsedProperty<'src>> for TextWithLanguage<Segments<'src>> {
258 type Error = Vec<TypedError<'src>>;
259
260 fn try_from(prop: ParsedProperty<'src>) -> Result<Self, Self::Error> {
261 let content = take_single_text(&prop.kind, prop.value)?;
262
263 let mut errors = Vec::new();
264 let mut language = None;
265 let mut x_parameters = Vec::new();
266 let mut retained_parameters = Vec::new();
267
268 for param in prop.parameters {
269 match param {
270 p @ Parameter::Language { .. } if language.is_some() => {
271 errors.push(TypedError::ParameterDuplicated {
272 span: p.span(),
273 parameter: p.kind().into(),
274 });
275 }
276 Parameter::Language { value, .. } => language = Some(value),
277
278 Parameter::XName(raw) => x_parameters.push(raw),
279 p @ Parameter::Unrecognized { .. } => retained_parameters.push(p),
280 p => {
281 retained_parameters.push(p);
283 }
284 }
285 }
286
287 if !errors.is_empty() {
289 return Err(errors);
290 }
291
292 Ok(Self {
293 content,
294 language,
295 x_parameters,
296 retained_parameters,
297 })
298 }
299}
300
301impl TextWithLanguage<Segments<'_>> {
302 #[must_use]
304 pub fn to_owned(&self) -> TextWithLanguage<String> {
305 TextWithLanguage {
306 content: self.content.to_owned(),
307 language: self.language.as_ref().map(Segments::to_owned),
308 x_parameters: self
309 .x_parameters
310 .iter()
311 .map(RawParameter::to_owned)
312 .collect(),
313 retained_parameters: self
314 .retained_parameters
315 .iter()
316 .map(Parameter::to_owned)
317 .collect(),
318 }
319 }
320}
321
322#[derive(Debug, Clone)]
333pub struct Text<S: StringStorage> {
334 pub content: ValueText<S>,
336
337 pub language: Option<S>,
339
340 pub altrep: Option<S>,
345
346 pub x_parameters: Vec<RawParameter<S>>,
348
349 pub retained_parameters: Vec<Parameter<S>>,
351}
352
353impl<'src> TryFrom<ParsedProperty<'src>> for Text<Segments<'src>> {
354 type Error = Vec<TypedError<'src>>;
355
356 fn try_from(prop: ParsedProperty<'src>) -> Result<Self, Self::Error> {
357 let content = take_single_text(&prop.kind, prop.value)?;
358
359 let mut errors = Vec::new();
360
361 let mut language = None;
363 let mut altrep = None;
364 let mut x_parameters = Vec::new();
365 let mut retained_parameters = Vec::new();
366
367 for param in prop.parameters {
368 match param {
369 p @ Parameter::Language { .. } if language.is_some() => {
370 errors.push(TypedError::ParameterDuplicated {
371 span: p.span(),
372 parameter: p.kind().into(),
373 });
374 }
375 Parameter::Language { value, .. } => language = Some(value),
376
377 p @ Parameter::AlternateText { .. } if altrep.is_some() => {
378 errors.push(TypedError::ParameterDuplicated {
379 span: p.span(),
380 parameter: p.kind().into(),
381 });
382 }
383 Parameter::AlternateText { value, .. } => altrep = Some(value),
384
385 Parameter::XName(raw) => x_parameters.push(raw),
386 p @ Parameter::Unrecognized { .. } => retained_parameters.push(p),
387 p => {
388 retained_parameters.push(p);
390 }
391 }
392 }
393
394 if !errors.is_empty() {
396 return Err(errors);
397 }
398
399 Ok(Self {
400 content,
401 language,
402 altrep,
403 x_parameters,
404 retained_parameters,
405 })
406 }
407}
408
409impl Text<Segments<'_>> {
410 #[must_use]
412 pub fn to_owned(&self) -> Text<String> {
413 Text {
414 content: self.content.to_owned(),
415 language: self.language.as_ref().map(Segments::to_owned),
416 altrep: self.altrep.as_ref().map(Segments::to_owned),
417 x_parameters: self
418 .x_parameters
419 .iter()
420 .map(RawParameter::to_owned)
421 .collect(),
422 retained_parameters: self
423 .retained_parameters
424 .iter()
425 .map(Parameter::to_owned)
426 .collect(),
427 }
428 }
429}
430
431impl Text<String> {
432 #[must_use]
437 pub fn new(value: String) -> Self {
438 Self {
439 content: ValueText::new(value),
440 language: None,
441 altrep: None,
442 x_parameters: Vec::new(),
443 retained_parameters: Vec::new(),
444 }
445 }
446}
447
448impl TextOnly<String> {
449 #[must_use]
454 pub fn new(value: String) -> Self {
455 Self {
456 content: ValueText::new(value),
457 x_parameters: Vec::new(),
458 retained_parameters: Vec::new(),
459 }
460 }
461}
462
463macro_rules! simple_property_wrapper {
483 (
484 $(#[$meta:meta])*
485 $vis:vis $name:ident <S> => $inner:ident
486 ) => {
487 $(#[$meta])*
488 #[derive(Debug, Clone)]
489 $vis struct $name<S: StringStorage> {
490 pub inner: $inner<S>,
492 pub span: S::Span,
494 }
495
496 impl<S> ::core::ops::Deref for $name<S>
497 where
498 S: StringStorage,
499 {
500 type Target = $inner<S>;
501
502 fn deref(&self) -> &Self::Target {
503 &self.inner
504 }
505 }
506
507 impl<S> ::core::ops::DerefMut for $name<S>
508 where
509 S: StringStorage,
510 {
511 fn deref_mut(&mut self) -> &mut Self::Target {
512 &mut self.inner
513 }
514 }
515
516 impl<'src> ::core::convert::TryFrom<crate::typed::ParsedProperty<'src>> for $name<crate::string_storage::Segments<'src>>
517 where
518 $inner<crate::string_storage::Segments<'src>>: ::core::convert::TryFrom<crate::typed::ParsedProperty<'src>, Error = Vec<crate::typed::TypedError<'src>>>,
519 {
520 type Error = Vec<crate::typed::TypedError<'src>>;
521
522 fn try_from(prop: crate::typed::ParsedProperty<'src>) -> Result<Self, Self::Error> {
523 if !matches!(prop.kind, crate::property::PropertyKind::$name) {
524 return Err(vec![crate::typed::TypedError::PropertyUnexpectedKind {
525 expected: crate::property::PropertyKind::$name,
526 found: prop.kind,
527 span: prop.span,
528 }]);
529 }
530
531 let span = prop.span;
532 <$inner<crate::string_storage::Segments<'src>>>::try_from(prop).map(|inner| $name { inner, span })
533 }
534 }
535
536 impl $name<crate::string_storage::Segments<'_>> {
537 #[must_use]
539 pub fn to_owned(&self) -> $name<String> {
540 $name {
541 inner: self.inner.to_owned(),
542 span: (),
543 }
544 }
545 }
546 };
547}
548
549macro_rules! define_prop_value_enum {
554 (
555 $(#[$meta:meta])*
556 $vis:vis enum $Name:ident {
557 $(
558 $(#[$vmeta:meta])*
559 $Variant:ident => $kw:ident
560 ),* $(,)?
561 }
562 ) => {
563 $(#[$meta])*
564 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
565 #[allow(missing_docs)]
566 $vis enum $Name {
567 $(
568 $(#[$vmeta])*
569 $Variant,
570 )*
571 }
572
573
574 impl<'src> TryFrom<crate::value::ValueText<Segments<'src>>> for $Name {
575 type Error = crate::value::ValueText<Segments<'src>>;
576
577 fn try_from(segs: crate::value::ValueText<Segments<'src>>) -> Result<Self, Self::Error> {
578 $(
579 if segs.eq_str_ignore_ascii_case($kw) {
580 return Ok(Self::$Variant);
581 }
582 )*
583 Err(segs)
584 }
585 }
586
587 impl ::core::fmt::Display for $Name {
588 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
589 match self {
590 $(
591 Self::$Variant => $kw.fmt(f),
592 )*
593 }
594 }
595 }
596 };
597}