1
use crate::common::{Encoding, Status, TimeTransparency, Value};
2
use crate::parser::param::{other_params, property_params};
3
use crate::parser::property::recur::prop_value_recur;
4
use crate::parser::property::uri::param_value_uri;
5
use crate::parser::types::{
6
    Action, ActionProperty, AttachProperty, AttachValue, AttendeeProperty, CategoriesProperty,
7
    Classification, ClassificationProperty, CommentProperty, ContactProperty, DateOrDateTime,
8
    DateOrDateTimeOrPeriod, DateTimeCompletedProperty, DateTimeCreatedProperty,
9
    DateTimeDueProperty, DateTimeEndProperty, DateTimeStampProperty, DateTimeStartProperty,
10
    DescriptionProperty, DurationOrDateTime, DurationProperty, ExceptionDateTimesProperty,
11
    FreeBusyTimeProperty, GeographicPositionProperty, LastModifiedProperty, LocationProperty,
12
    OrganizerProperty, ParamValue, PercentCompleteProperty, PriorityProperty,
13
    RecurrenceDateTimesProperty, RecurrenceIdProperty, RecurrenceRuleProperty, RelatedToProperty,
14
    RepeatProperty, RequestStatusProperty, ResourcesProperty, SequenceProperty, StatusProperty,
15
    SummaryProperty, TimeTransparencyProperty, TimeZoneIdProperty, TimeZoneNameProperty,
16
    TimeZoneOffsetProperty, TimeZoneUrlProperty, TriggerProperty, UniqueIdentifierProperty,
17
    UrlProperty,
18
};
19
use crate::parser::{iana_token, read_int, x_name, Error, InnerError};
20
use crate::parser::{
21
    prop_value_binary, prop_value_calendar_user_address, prop_value_date, prop_value_date_time,
22
    prop_value_duration, prop_value_float, prop_value_integer, prop_value_period, prop_value_text,
23
    prop_value_utc_offset,
24
};
25
use nom::branch::alt;
26
use nom::bytes::complete::{tag_no_case, take_while1};
27
use nom::bytes::streaming::tag;
28
use nom::character::streaming::char;
29
use nom::combinator::{cut, map_res, opt, recognize, verify};
30
use nom::error::ParseError;
31
use nom::multi::{fold_many_m_n, separated_list1};
32
use nom::{AsChar, IResult, Parser};
33

            
34
/// Parse an ATTACH property.
35
///
36
/// RFC 5545, section 3.8.1.1
37
507
pub fn prop_attach<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], AttachProperty<'a>, E>
38
507
where
39
507
    E: ParseError<&'a [u8]>
40
507
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
41
507
        + From<Error<'a>>,
42
507
{
43
34
    let (input, (_, params, _)) =
44
507
        (tag_no_case("ATTACH"), cut(property_params), char(':')).parse(input)?;
45

            
46
44
    let is_base_64 = params.iter().any(|p| {
47
34
        matches!(
48
6
            p,
49
            ParamValue::Encoding {
50
                encoding: Encoding::Base64,
51
            }
52
        )
53
44
    });
54
34

            
55
46
    let is_binary = params.iter().any(|p| {
56
28
        matches!(
57
10
            p,
58
            ParamValue::ValueType {
59
                value: Value::Binary,
60
            }
61
        )
62
46
    });
63
34

            
64
34
    // Use OR here rather than AND. It's not valid to set one of these and not the other so assume the
65
34
    // value is more likely to be binary if one is set and let the error happen later if so.
66
34
    if is_base_64 || is_binary {
67
8
        let (input, (v, _)) = (cut(prop_value_binary), tag("\r\n")).parse(input)?;
68

            
69
8
        Ok((
70
8
            input,
71
8
            AttachProperty {
72
8
                params,
73
8
                value: AttachValue::Binary(v),
74
8
            },
75
8
        ))
76
    } else {
77
26
        let (input, (v, _)) = (cut(recognize(param_value_uri)), tag("\r\n")).parse(input)?;
78

            
79
26
        Ok((
80
26
            input,
81
26
            AttachProperty {
82
26
                params,
83
26
                value: AttachValue::Uri(v),
84
26
            },
85
26
        ))
86
    }
87
507
}
88

            
89
/// Parse a CATEGORIES property.
90
///
91
/// RFC 5545, section 3.8.1.2
92
358
pub fn prop_categories<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], CategoriesProperty<'a>, E>
93
358
where
94
358
    E: ParseError<&'a [u8]>
95
358
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
96
358
        + From<Error<'a>>,
97
358
{
98
358
    let (input, (_, (params, _, value, _))) = (
99
358
        tag_no_case("CATEGORIES"),
100
358
        cut((
101
358
            property_params,
102
358
            char(':'),
103
358
            separated_list1(char(','), prop_value_text),
104
358
            tag("\r\n"),
105
358
        )),
106
358
    )
107
358
        .parse(input)?;
108

            
109
23
    Ok((input, CategoriesProperty { params, value }))
110
358
}
111

            
112
/// Parse a CLASS property.
113
///
114
/// RFC 5545, section 3.8.1.3
115
926
pub fn prop_classification<'a, E>(
116
926
    input: &'a [u8],
117
926
) -> IResult<&'a [u8], ClassificationProperty<'a>, E>
118
926
where
119
926
    E: ParseError<&'a [u8]> + From<Error<'a>>,
120
926
{
121
926
    let (input, (_, (other_params, _, value, _))) = (
122
926
        tag_no_case("CLASS"),
123
926
        cut((
124
926
            other_params,
125
926
            char(':'),
126
926
            alt((
127
926
                tag_no_case("PUBLIC").map(|_| Classification::Public),
128
926
                tag_no_case("PRIVATE").map(|_| Classification::Private),
129
926
                tag_no_case("CONFIDENTIAL").map(|_| Classification::Confidential),
130
926
                x_name.map(Classification::XName),
131
926
                iana_token.map(Classification::IanaToken),
132
926
            )),
133
926
            tag("\r\n"),
134
926
        )),
135
926
    )
136
926
        .parse(input)?;
137

            
138
35
    Ok((
139
35
        input,
140
35
        ClassificationProperty {
141
35
            other_params,
142
35
            value,
143
35
        },
144
35
    ))
145
926
}
146

            
147
/// Parse a COMMENT property.
148
///
149
/// RFC 5545, section 3.8.1.4
150
513
pub fn prop_comment<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], CommentProperty<'a>, E>
151
513
where
152
513
    E: ParseError<&'a [u8]>
153
513
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
154
513
        + From<Error<'a>>,
155
513
{
156
513
    let (input, (_, (params, _, value, _))) = (
157
513
        tag_no_case("COMMENT"),
158
513
        cut((property_params, char(':'), prop_value_text, tag("\r\n"))),
159
513
    )
160
513
        .parse(input)?;
161

            
162
16
    Ok((input, CommentProperty { params, value }))
163
513
}
164

            
165
/// Parse a DESCRIPTION property.
166
///
167
/// RFC 5545, section 3.8.1.5
168
902
pub fn prop_description<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], DescriptionProperty<'a>, E>
169
902
where
170
902
    E: ParseError<&'a [u8]>
171
902
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
172
902
        + From<Error<'a>>,
173
902
{
174
902
    let (input, (_, (params, _, value, _))) = (
175
902
        tag_no_case("DESCRIPTION"),
176
902
        cut((
177
902
            property_params,
178
902
            char(':'),
179
902
            prop_value_text.map(|v| v),
180
902
            tag("\r\n"),
181
902
        )),
182
902
    )
183
902
        .parse(input)?;
184

            
185
79
    Ok((input, DescriptionProperty { params, value }))
186
902
}
187

            
188
/// Parse a GEO property.
189
///
190
/// RFC 5545, section 3.8.1.6
191
707
pub fn prop_geographic_position<'a, E>(
192
707
    input: &'a [u8],
193
707
) -> IResult<&'a [u8], GeographicPositionProperty<'a>, E>
194
707
where
195
707
    E: ParseError<&'a [u8]> + From<Error<'a>>,
196
707
{
197
707
    let (input, (_, (other_params, _, (latitude, _, longitude), _))) = (
198
707
        tag_no_case("GEO"),
199
707
        cut((
200
707
            other_params,
201
707
            char(':'),
202
707
            (prop_value_float, char(';'), prop_value_float),
203
707
            tag("\r\n"),
204
707
        )),
205
707
    )
206
707
        .parse(input)?;
207

            
208
14
    Ok((
209
14
        input,
210
14
        GeographicPositionProperty {
211
14
            other_params,
212
14
            latitude,
213
14
            longitude,
214
14
        },
215
14
    ))
216
707
}
217

            
218
/// Parse a LOCATION property.
219
///
220
/// RFC 5545, section 3.8.1.7
221
685
pub fn prop_location<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], LocationProperty<'a>, E>
222
685
where
223
685
    E: ParseError<&'a [u8]>
224
685
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
225
685
        + From<Error<'a>>,
226
685
{
227
685
    let (input, (_, (params, _, value, _))) = (
228
685
        tag_no_case("LOCATION"),
229
685
        cut((property_params, char(':'), prop_value_text, tag("\r\n"))),
230
685
    )
231
685
        .parse(input)?;
232

            
233
19
    Ok((input, LocationProperty { params, value }))
234
685
}
235

            
236
/// Parse a PERCENT-COMPLETE property.
237
///
238
/// RFC 5545, section 3.8.1.8
239
140
pub fn prop_percent_complete<'a, E>(
240
140
    input: &'a [u8],
241
140
) -> IResult<&'a [u8], PercentCompleteProperty<'a>, E>
242
140
where
243
140
    E: ParseError<&'a [u8]> + From<Error<'a>>,
244
140
{
245
140
    let (input, (_, (other_params, _, value, _))) = (
246
140
        tag_no_case("PERCENT-COMPLETE"),
247
140
        cut((
248
140
            other_params,
249
140
            char(':'),
250
140
            verify(prop_value_integer, |v| 0 <= *v && *v <= 100).map(|v| v as u8),
251
140
            tag("\r\n"),
252
140
        )),
253
140
    )
254
140
        .parse(input)?;
255

            
256
8
    Ok((
257
8
        input,
258
8
        PercentCompleteProperty {
259
8
            other_params,
260
8
            value,
261
8
        },
262
8
    ))
263
140
}
264

            
265
/// Parse a PRIORITY property.
266
///
267
/// RFC 5545, section 3.8.1.9
268
645
pub fn prop_priority<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], PriorityProperty<'a>, E>
269
645
where
270
645
    E: ParseError<&'a [u8]> + From<Error<'a>>,
271
645
{
272
645
    let (input, (_, (other_params, _, value, _))) = (
273
645
        tag_no_case("PRIORITY"),
274
645
        cut((
275
645
            other_params,
276
645
            char(':'),
277
645
            verify(prop_value_integer, |v| 0 <= *v && *v <= 9).map(|v| v as u8),
278
645
            tag("\r\n"),
279
645
        )),
280
645
    )
281
645
        .parse(input)?;
282

            
283
16
    Ok((
284
16
        input,
285
16
        PriorityProperty {
286
16
            other_params,
287
16
            value,
288
16
        },
289
16
    ))
290
645
}
291

            
292
/// Parse a RESOURCES property.
293
///
294
/// RFC 5545, section 3.8.1.10
295
279
pub fn prop_resources<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], ResourcesProperty<'a>, E>
296
279
where
297
279
    E: ParseError<&'a [u8]>
298
279
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
299
279
        + From<Error<'a>>,
300
279
{
301
279
    let (input, (_, (params, _, value, _))) = (
302
279
        tag_no_case("RESOURCES"),
303
279
        cut((
304
279
            property_params,
305
279
            char(':'),
306
279
            separated_list1(char(','), prop_value_text),
307
279
            tag("\r\n"),
308
279
        )),
309
279
    )
310
279
        .parse(input)?;
311

            
312
6
    Ok((input, ResourcesProperty { params, value }))
313
279
}
314

            
315
/// Parse a STATUS property.
316
///
317
/// RFC 5545, section 3.8.1.11
318
681
pub fn prop_status<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], StatusProperty<'a>, E>
319
681
where
320
681
    E: ParseError<&'a [u8]> + From<Error<'a>>,
321
681
{
322
681
    let (input, (_, (other_params, _, value, _))) = (
323
681
        tag_no_case("STATUS"),
324
681
        cut((
325
681
            other_params,
326
681
            char(':'),
327
681
            alt((
328
681
                tag_no_case("TENTATIVE").map(|_| Status::Tentative),
329
681
                tag_no_case("CONFIRMED").map(|_| Status::Confirmed),
330
681
                tag_no_case("CANCELLED").map(|_| Status::Cancelled),
331
681
                tag_no_case("NEEDS-ACTION").map(|_| Status::NeedsAction),
332
681
                tag_no_case("COMPLETED").map(|_| Status::Completed),
333
681
                tag_no_case("IN-PROCESS").map(|_| Status::InProcess),
334
681
                tag_no_case("DRAFT").map(|_| Status::Draft),
335
681
                tag_no_case("FINAL").map(|_| Status::Final),
336
681
            )),
337
681
            tag("\r\n"),
338
681
        )),
339
681
    )
340
681
        .parse(input)?;
341

            
342
26
    Ok((
343
26
        input,
344
26
        StatusProperty {
345
26
            other_params,
346
26
            value,
347
26
        },
348
26
    ))
349
681
}
350

            
351
/// Parse a SUMMARY property.
352
///
353
/// RFC 5545, section 3.8.1.12
354
737
pub fn prop_summary<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], SummaryProperty<'a>, E>
355
737
where
356
737
    E: ParseError<&'a [u8]>
357
737
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
358
737
        + From<Error<'a>>,
359
737
{
360
737
    let (input, (_, (params, _, value, _))) = (
361
737
        tag_no_case("SUMMARY"),
362
737
        cut((property_params, char(':'), prop_value_text, tag("\r\n"))),
363
737
    )
364
737
        .parse(input)?;
365

            
366
53
    Ok((input, SummaryProperty { params, value }))
367
737
}
368

            
369
/// Parse a COMPLETED property.
370
///
371
/// RFC 5545, section 3.8.2.1
372
192
pub fn prop_date_time_completed<'a, E>(
373
192
    input: &'a [u8],
374
192
) -> IResult<&'a [u8], DateTimeCompletedProperty<'a>, E>
375
192
where
376
192
    E: ParseError<&'a [u8]> + From<Error<'a>>,
377
192
{
378
192
    let (input, (_, (other_params, _, value, _))) = (
379
192
        tag_no_case("COMPLETED"),
380
192
        cut((other_params, char(':'), prop_value_date_time, tag("\r\n"))),
381
192
    )
382
192
        .parse(input)?;
383

            
384
6
    Ok((
385
6
        input,
386
6
        DateTimeCompletedProperty {
387
6
            other_params,
388
6
            value,
389
6
        },
390
6
    ))
391
192
}
392

            
393
/// Parse a DTEND property.
394
///
395
/// RFC 5545, section 3.8.2.2
396
392
pub fn prop_date_time_end<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], DateTimeEndProperty<'a>, E>
397
392
where
398
392
    E: ParseError<&'a [u8]>
399
392
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
400
392
        + From<Error<'a>>,
401
392
{
402
392
    let (input, (_, (params, _, value, _))) = (
403
392
        tag_no_case("DTEND"),
404
392
        cut((
405
392
            property_params,
406
392
            char(':'),
407
392
            alt((
408
392
                prop_value_date_time.map(DateOrDateTime::DateTime),
409
392
                prop_value_date.map(DateOrDateTime::Date),
410
392
            )),
411
392
            tag("\r\n"),
412
392
        )),
413
392
    )
414
392
        .parse(input)?;
415

            
416
37
    Ok((input, DateTimeEndProperty { params, value }))
417
392
}
418

            
419
/// Parse a DUE property.
420
///
421
/// RFC 5545, section 3.8.2.3
422
84
pub fn prop_date_time_due<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], DateTimeDueProperty<'a>, E>
423
84
where
424
84
    E: ParseError<&'a [u8]>
425
84
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
426
84
        + From<Error<'a>>,
427
84
{
428
84
    let (input, (_, (params, _, value, _))) = (
429
84
        tag_no_case("DUE"),
430
84
        cut((
431
84
            property_params,
432
84
            char(':'),
433
84
            alt((
434
84
                prop_value_date_time.map(DateOrDateTime::DateTime),
435
84
                prop_value_date.map(DateOrDateTime::Date),
436
84
            )),
437
84
            tag("\r\n"),
438
84
        )),
439
84
    )
440
84
        .parse(input)?;
441

            
442
18
    Ok((input, DateTimeDueProperty { params, value }))
443
84
}
444

            
445
/// Parse a DTSTART property.
446
///
447
/// RFC 5545, section 3.8.2.4
448
1399
pub fn prop_date_time_start<'a, E>(
449
1399
    input: &'a [u8],
450
1399
) -> IResult<&'a [u8], DateTimeStartProperty<'a>, E>
451
1399
where
452
1399
    E: ParseError<&'a [u8]>
453
1399
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
454
1399
        + From<Error<'a>>,
455
1399
{
456
1399
    let (input, (_, (params, _, value, _))) = (
457
1399
        tag_no_case("DTSTART"),
458
1399
        cut((
459
1399
            property_params,
460
1399
            char(':'),
461
1399
            alt((
462
1399
                prop_value_date_time.map(DateOrDateTime::DateTime),
463
1399
                prop_value_date.map(DateOrDateTime::Date),
464
1399
            )),
465
1399
            tag("\r\n"),
466
1399
        )),
467
1399
    )
468
1399
        .parse(input)?;
469

            
470
153
    Ok((input, DateTimeStartProperty { params, value }))
471
1399
}
472

            
473
/// Parse a DURATION property.
474
///
475
/// RFC 5545, section 3.8.2.5
476
541
pub fn prop_duration<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], DurationProperty<'a>, E>
477
541
where
478
541
    E: ParseError<&'a [u8]> + From<Error<'a>>,
479
541
{
480
541
    let (input, (_, (other_params, _, value, _))) = (
481
541
        tag_no_case("DURATION"),
482
541
        cut((other_params, char(':'), prop_value_duration, tag("\r\n"))),
483
541
    )
484
541
        .parse(input)?;
485

            
486
50
    Ok((
487
50
        input,
488
50
        DurationProperty {
489
50
            other_params,
490
50
            value,
491
50
        },
492
50
    ))
493
541
}
494

            
495
/// Parse a FREEBUSY property.
496
///
497
/// RFC 5545, section 3.8.2.6
498
36
pub fn prop_free_busy_time<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], FreeBusyTimeProperty<'a>, E>
499
36
where
500
36
    E: ParseError<&'a [u8]>
501
36
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
502
36
        + From<Error<'a>>,
503
36
{
504
36
    let (input, (_, (params, _, value, _))) = (
505
36
        tag_no_case("FREEBUSY"),
506
36
        cut((
507
36
            property_params,
508
36
            char(':'),
509
36
            separated_list1(char(','), prop_value_period),
510
36
            tag("\r\n"),
511
36
        )),
512
36
    )
513
36
        .parse(input)?;
514

            
515
14
    Ok((input, FreeBusyTimeProperty { params, value }))
516
36
}
517

            
518
/// Parse a TRANSP property.
519
///
520
/// RFC 5545, section 3.8.2.7
521
478
pub fn prop_time_transparency<'a, E>(
522
478
    input: &'a [u8],
523
478
) -> IResult<&'a [u8], TimeTransparencyProperty<'a>, E>
524
478
where
525
478
    E: ParseError<&'a [u8]> + From<Error<'a>>,
526
478
{
527
478
    let (input, (_, (other_params, _, value, _))) = (
528
478
        tag_no_case("TRANSP"),
529
478
        cut((
530
478
            other_params,
531
478
            char(':'),
532
478
            alt((
533
478
                tag_no_case("OPAQUE").map(|_| TimeTransparency::Opaque),
534
478
                tag_no_case("TRANSPARENT").map(|_| TimeTransparency::Transparent),
535
478
            )),
536
478
            tag("\r\n"),
537
478
        )),
538
478
    )
539
478
        .parse(input)?;
540

            
541
16
    Ok((
542
16
        input,
543
16
        TimeTransparencyProperty {
544
16
            other_params,
545
16
            value,
546
16
        },
547
16
    ))
548
478
}
549

            
550
/// Parse a TZID property.
551
///
552
/// RFC 5545, section 3.8.3.1
553
168
pub fn prop_time_zone_id<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], TimeZoneIdProperty<'a>, E>
554
168
where
555
168
    E: ParseError<&'a [u8]> + From<Error<'a>>,
556
168
{
557
168
    let (input, (_, (other_params, _, (unique, value), _))) = (
558
168
        tag_no_case("TZID"),
559
168
        cut((
560
168
            other_params,
561
168
            char(':'),
562
168
            (opt(char('/')), prop_value_text),
563
168
            tag("\r\n"),
564
168
        )),
565
168
    )
566
168
        .parse(input)?;
567

            
568
35
    Ok((
569
35
        input,
570
35
        TimeZoneIdProperty {
571
35
            other_params,
572
35
            unique_registry_id: unique.is_some(),
573
35
            value,
574
35
        },
575
35
    ))
576
168
}
577

            
578
/// Parse a TZNAME property.
579
///
580
/// RFC 5545, section 3.8.3.2
581
134
pub fn prop_time_zone_name<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], TimeZoneNameProperty<'a>, E>
582
134
where
583
134
    E: ParseError<&'a [u8]>
584
134
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
585
134
        + From<Error<'a>>,
586
134
{
587
134
    let (input, (_, (params, _, value, _))) = (
588
134
        tag_no_case("TZNAME"),
589
134
        cut((property_params, char(':'), prop_value_text, tag("\r\n"))),
590
134
    )
591
134
        .parse(input)?;
592

            
593
56
    Ok((input, TimeZoneNameProperty { params, value }))
594
134
}
595

            
596
/// Parse a TZOFFSETFROM property.
597
///
598
/// RFC 5545, section 3.8.3.3
599
242
pub fn prop_time_zone_offset_from<'a, E>(
600
242
    input: &'a [u8],
601
242
) -> IResult<&'a [u8], TimeZoneOffsetProperty<'a>, E>
602
242
where
603
242
    E: ParseError<&'a [u8]> + From<Error<'a>>,
604
242
{
605
242
    let (input, (_, (other_params, _, value, _))) = (
606
242
        tag_no_case("TZOFFSETFROM"),
607
242
        cut((other_params, char(':'), prop_value_utc_offset, tag("\r\n"))),
608
242
    )
609
242
        .parse(input)?;
610

            
611
64
    Ok((
612
64
        input,
613
64
        TimeZoneOffsetProperty {
614
64
            other_params,
615
64
            value,
616
64
        },
617
64
    ))
618
242
}
619

            
620
/// Parse a TZOFFSETTO property.
621
///
622
/// RFC 5545, section 3.8.3.4
623
304
pub fn prop_time_zone_offset_to<'a, E>(
624
304
    input: &'a [u8],
625
304
) -> IResult<&'a [u8], TimeZoneOffsetProperty<'a>, E>
626
304
where
627
304
    E: ParseError<&'a [u8]> + From<Error<'a>>,
628
304
{
629
304
    let (input, (_, (other_params, _, value, _))) = (
630
304
        tag_no_case("TZOFFSETTO"),
631
304
        cut((other_params, char(':'), prop_value_utc_offset, tag("\r\n"))),
632
304
    )
633
304
        .parse(input)?;
634

            
635
64
    Ok((
636
64
        input,
637
64
        TimeZoneOffsetProperty {
638
64
            other_params,
639
64
            value,
640
64
        },
641
64
    ))
642
304
}
643

            
644
/// Parse a TZURL property.
645
///
646
/// RFC 5545, section 3.8.3.5
647
115
pub fn prop_time_zone_url<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], TimeZoneUrlProperty<'a>, E>
648
115
where
649
115
    E: ParseError<&'a [u8]>
650
115
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
651
115
        + From<Error<'a>>,
652
115
{
653
115
    let (input, (_, (other_params, _, value, _))) = (
654
115
        tag_no_case("TZURL"),
655
115
        cut((
656
115
            other_params,
657
115
            char(':'),
658
115
            cut(recognize(param_value_uri)),
659
115
            tag("\r\n"),
660
115
        )),
661
115
    )
662
115
        .parse(input)?;
663

            
664
10
    Ok((
665
10
        input,
666
10
        TimeZoneUrlProperty {
667
10
            other_params,
668
10
            value,
669
10
        },
670
10
    ))
671
115
}
672

            
673
/// Parse an ATTENDEE property.
674
///
675
/// RFC 5545, section 3.8.4.1
676
485
pub fn prop_attendee<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], AttendeeProperty<'a>, E>
677
485
where
678
485
    E: ParseError<&'a [u8]>
679
485
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
680
485
        + From<Error<'a>>,
681
485
{
682
485
    let (input, (_, (params, _, uri, _))) = (
683
485
        tag_no_case("ATTENDEE"),
684
485
        cut((
685
485
            property_params,
686
485
            char(':'),
687
485
            cut(recognize(prop_value_calendar_user_address)),
688
485
            tag("\r\n"),
689
485
        )),
690
485
    )
691
485
        .parse(input)?;
692

            
693
27
    Ok((input, AttendeeProperty { params, value: uri }))
694
485
}
695

            
696
/// Parse a CONTACT property.
697
///
698
/// RFC 5545, section 3.8.4.2
699
431
pub fn prop_contact<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], ContactProperty<'a>, E>
700
431
where
701
431
    E: ParseError<&'a [u8]>
702
431
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
703
431
        + From<Error<'a>>,
704
431
{
705
431
    let (input, (_, (params, _, value, _))) = (
706
431
        tag_no_case("CONTACT"),
707
431
        cut((property_params, char(':'), prop_value_text, tag("\r\n"))),
708
431
    )
709
431
        .parse(input)?;
710

            
711
16
    Ok((input, ContactProperty { params, value }))
712
431
}
713

            
714
/// Parse an ORGANIZER property.
715
///
716
/// RFC 5545, section 3.8.4.3
717
826
pub fn prop_organizer<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], OrganizerProperty<'a>, E>
718
826
where
719
826
    E: ParseError<&'a [u8]>
720
826
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
721
826
        + From<Error<'a>>,
722
826
{
723
826
    let (input, (_, (params, _, uri, _))) = (
724
826
        tag_no_case("ORGANIZER"),
725
826
        cut((
726
826
            property_params,
727
826
            char(':'),
728
826
            recognize(prop_value_calendar_user_address),
729
826
            tag("\r\n"),
730
826
        )),
731
826
    )
732
826
        .parse(input)?;
733

            
734
43
    Ok((input, OrganizerProperty { params, value: uri }))
735
826
}
736

            
737
/// Parse a RECURRENCE-ID property.
738
///
739
/// RFC 5545, section 3.8.4.4
740
664
pub fn prop_recurrence_id<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], RecurrenceIdProperty<'a>, E>
741
664
where
742
664
    E: ParseError<&'a [u8]>
743
664
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
744
664
        + From<Error<'a>>,
745
664
{
746
664
    let (input, (_, (params, _, value, _))) = (
747
664
        tag_no_case("RECURRENCE-ID"),
748
664
        cut((
749
664
            property_params,
750
664
            char(':'),
751
664
            alt((
752
664
                prop_value_date_time.map(DateOrDateTime::DateTime),
753
664
                prop_value_date.map(DateOrDateTime::Date),
754
664
            )),
755
664
            tag("\r\n"),
756
664
        )),
757
664
    )
758
664
        .parse(input)?;
759

            
760
22
    Ok((input, RecurrenceIdProperty { params, value }))
761
664
}
762

            
763
/// Parse a RELATED-TO property.
764
///
765
/// RFC 5545, section 3.8.4.5
766
307
pub fn prop_related_to<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], RelatedToProperty<'a>, E>
767
307
where
768
307
    E: ParseError<&'a [u8]>
769
307
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
770
307
        + From<Error<'a>>,
771
307
{
772
307
    let (input, (_, (params, _, value, _))) = (
773
307
        tag_no_case("RELATED-TO"),
774
307
        cut((property_params, char(':'), prop_value_text, tag("\r\n"))),
775
307
    )
776
307
        .parse(input)?;
777

            
778
8
    Ok((input, RelatedToProperty { params, value }))
779
307
}
780

            
781
/// Parse a URL property.
782
///
783
/// RFC 5545, section 3.8.4.6
784
658
pub fn prop_url<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], UrlProperty<'a>, E>
785
658
where
786
658
    E: ParseError<&'a [u8]>
787
658
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
788
658
        + From<Error<'a>>,
789
658
{
790
658
    let (input, (_, (other_params, _, value, _))) = (
791
658
        tag_no_case("URL"),
792
658
        cut((other_params, char(':'), param_value_uri, tag("\r\n"))),
793
658
    )
794
658
        .parse(input)?;
795

            
796
30
    Ok((
797
30
        input,
798
30
        UrlProperty {
799
30
            other_params,
800
30
            value,
801
30
        },
802
30
    ))
803
658
}
804

            
805
/// Parse a UID property.
806
///
807
/// RFC 5545, section 3.8.4.7
808
1244
pub fn prop_unique_identifier<'a, E>(
809
1244
    input: &'a [u8],
810
1244
) -> IResult<&'a [u8], UniqueIdentifierProperty<'a>, E>
811
1244
where
812
1244
    E: ParseError<&'a [u8]> + From<Error<'a>>,
813
1244
{
814
1244
    let (input, (_, (other_params, _, value, _))) = (
815
1244
        tag_no_case("UID"),
816
1244
        cut((other_params, char(':'), prop_value_text, tag("\r\n"))),
817
1244
    )
818
1244
        .parse(input)?;
819

            
820
169
    Ok((
821
169
        input,
822
169
        UniqueIdentifierProperty {
823
169
            other_params,
824
169
            value,
825
169
        },
826
169
    ))
827
1244
}
828

            
829
/// Parse an EXDATE property.
830
///
831
/// RFC 5545, section 3.8.5.1
832
319
pub fn prop_exception_date_times<'a, E>(
833
319
    input: &'a [u8],
834
319
) -> IResult<&'a [u8], ExceptionDateTimesProperty<'a>, E>
835
319
where
836
319
    E: ParseError<&'a [u8]>
837
319
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
838
319
        + From<Error<'a>>,
839
319
{
840
319
    let (input, (_, (params, _, value, _))) = (
841
319
        tag_no_case("EXDATE"),
842
319
        cut((
843
319
            property_params,
844
319
            char(':'),
845
319
            separated_list1(
846
319
                char(','),
847
319
                alt((
848
319
                    prop_value_date_time.map(DateOrDateTime::DateTime),
849
319
                    prop_value_date.map(DateOrDateTime::Date),
850
319
                )),
851
319
            ),
852
319
            tag("\r\n"),
853
319
        )),
854
319
    )
855
319
        .parse(input)?;
856

            
857
10
    Ok((input, ExceptionDateTimesProperty { params, value }))
858
319
}
859

            
860
/// Parse an RDATE property.
861
///
862
/// RFC 5545, section 3.8.5.2
863
437
pub fn prop_recurrence_date_times<'a, E>(
864
437
    input: &'a [u8],
865
437
) -> IResult<&'a [u8], RecurrenceDateTimesProperty<'a>, E>
866
437
where
867
437
    E: ParseError<&'a [u8]>
868
437
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
869
437
        + From<Error<'a>>,
870
437
{
871
437
    let (input, (_, (params, _, value, _))) = (
872
437
        tag_no_case("RDATE"),
873
437
        cut((
874
437
            property_params,
875
437
            char(':'),
876
437
            separated_list1(
877
437
                char(','),
878
437
                alt((
879
437
                    prop_value_period.map(DateOrDateTimeOrPeriod::Period),
880
437
                    prop_value_date_time.map(DateOrDateTimeOrPeriod::DateTime),
881
437
                    prop_value_date.map(DateOrDateTimeOrPeriod::Date),
882
437
                )),
883
437
            ),
884
437
            tag("\r\n"),
885
437
        )),
886
437
    )
887
437
        .parse(input)?;
888

            
889
20
    Ok((input, RecurrenceDateTimesProperty { params, value }))
890
437
}
891

            
892
/// Parse an RRULE property.
893
///
894
/// RFC 5545, section 3.8.5.3
895
758
pub fn prop_recurrence_rule<'a, E>(
896
758
    input: &'a [u8],
897
758
) -> IResult<&'a [u8], RecurrenceRuleProperty<'a>, E>
898
758
where
899
758
    E: ParseError<&'a [u8]>
900
758
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
901
758
        + From<Error<'a>>,
902
758
{
903
758
    let (input, (_, (other_params, _, value, _))) = (
904
758
        tag_no_case("RRULE"),
905
758
        cut((other_params, char(':'), prop_value_recur, tag("\r\n"))),
906
758
    )
907
758
        .parse(input)?;
908

            
909
186
    Ok((
910
186
        input,
911
186
        RecurrenceRuleProperty {
912
186
            other_params,
913
186
            value,
914
186
        },
915
186
    ))
916
758
}
917

            
918
/// Parse an ACTION property.
919
///
920
/// RFC 5545, section 3.8.6.1
921
272
pub fn prop_action<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], ActionProperty<'a>, E>
922
272
where
923
272
    E: ParseError<&'a [u8]> + From<Error<'a>>,
924
272
{
925
272
    let (input, (_, (other_params, _, value, _))) = (
926
272
        tag_no_case("ACTION"),
927
272
        cut((
928
272
            other_params,
929
272
            char(':'),
930
272
            alt((
931
272
                tag_no_case("AUDIO").map(|_| Action::Audio),
932
272
                tag_no_case("DISPLAY").map(|_| Action::Display),
933
272
                tag_no_case("EMAIL").map(|_| Action::Email),
934
272
                x_name.map(Action::XName),
935
272
                iana_token.map(Action::IanaToken),
936
272
            )),
937
272
            tag("\r\n"),
938
272
        )),
939
272
    )
940
272
        .parse(input)?;
941

            
942
46
    Ok((
943
46
        input,
944
46
        ActionProperty {
945
46
            other_params,
946
46
            value,
947
46
        },
948
46
    ))
949
272
}
950

            
951
/// Parse a REPEAT property.
952
///
953
/// RFC 5545, section 3.8.6.2
954
156
pub fn prop_repeat<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], RepeatProperty<'a>, E>
955
156
where
956
156
    E: ParseError<&'a [u8]> + From<Error<'a>>,
957
156
{
958
156
    let (input, (_, (other_params, _, value, _))) = (
959
156
        tag_no_case("REPEAT"),
960
156
        cut((
961
156
            other_params,
962
156
            char(':'),
963
156
            prop_value_integer.map(|v| v as u32),
964
156
            tag("\r\n"),
965
156
        )),
966
156
    )
967
156
        .parse(input)?;
968

            
969
34
    Ok((
970
34
        input,
971
34
        RepeatProperty {
972
34
            other_params,
973
34
            value,
974
34
        },
975
34
    ))
976
156
}
977

            
978
/// Parse a TRIGGER property.
979
///
980
/// RFC 5545, section 3.8.6.3
981
232
pub fn prop_trigger<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], TriggerProperty<'a>, E>
982
232
where
983
232
    E: ParseError<&'a [u8]>
984
232
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
985
232
        + From<Error<'a>>,
986
232
{
987
46
    let (input, (_, (params, _))) =
988
232
        (tag_no_case("TRIGGER"), cut((property_params, char(':')))).parse(input)?;
989

            
990
46
    let value_choice = params
991
46
        .iter()
992
46
        .filter_map(|p| match p {
993
            ParamValue::ValueType {
994
                value: Value::Duration,
995
4
            } => Some(1),
996
            ParamValue::ValueType {
997
                value: Value::DateTime,
998
10
            } => Some(2),
999
18
            _ => None,
56
        })
46
        .collect::<Vec<_>>();
46
    let (input, value) = match value_choice.as_slice() {
46
        [1] | [] => cut(prop_value_duration)
36
            .map(DurationOrDateTime::Duration)
36
            .parse(input),
10
        [2] => cut(prop_value_date_time)
10
            .map(DurationOrDateTime::DateTime)
10
            .parse(input),
        _ => {
            return Err(nom::Err::Error(
                Error::new(input, InnerError::InvalidValueParam).into(),
            ))
        }
    }?;
46
    let (input, _) = cut(tag("\r\n")).parse(input)?;
46
    Ok((input, TriggerProperty { params, value }))
232
}
/// Parse a CREATED property.
///
/// RFC 5545, section 3.8.7.1
891
pub fn prop_date_time_created<'a, E>(
891
    input: &'a [u8],
891
) -> IResult<&'a [u8], DateTimeCreatedProperty<'a>, E>
891
where
891
    E: ParseError<&'a [u8]> + From<Error<'a>>,
891
{
891
    let (input, (_, (other_params, _, value, _))) = (
891
        tag_no_case("CREATED"),
891
        cut((other_params, char(':'), prop_value_date_time, tag("\r\n"))),
891
    )
891
        .parse(input)?;
25
    Ok((
25
        input,
25
        DateTimeCreatedProperty {
25
            other_params,
25
            value,
25
        },
25
    ))
891
}
/// Parse a DTSTAMP property.
///
/// RFC 5545, section 3.8.7.2
1411
pub fn prop_date_time_stamp<'a, E>(
1411
    input: &'a [u8],
1411
) -> IResult<&'a [u8], DateTimeStampProperty<'a>, E>
1411
where
1411
    E: ParseError<&'a [u8]> + From<Error<'a>>,
1411
{
1411
    let (input, (_, (other_params, _, value, _))) = (
1411
        tag_no_case("DTSTAMP"),
1411
        cut((other_params, char(':'), prop_value_date_time, tag("\r\n"))),
1411
    )
1411
        .parse(input)?;
169
    Ok((
169
        input,
169
        DateTimeStampProperty {
169
            other_params,
169
            value,
169
        },
169
    ))
1411
}
/// Parse a LAST-MODIFIED property.
///
/// RFC 5545, section 3.8.7.3
920
pub fn prop_last_modified<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], LastModifiedProperty<'a>, E>
920
where
920
    E: ParseError<&'a [u8]> + From<Error<'a>>,
920
{
920
    let (input, (_, (other_params, _, value, _))) = (
920
        tag_no_case("LAST-MODIFIED"),
920
        cut((other_params, char(':'), prop_value_date_time, tag("\r\n"))),
920
    )
920
        .parse(input)?;
40
    Ok((
40
        input,
40
        LastModifiedProperty {
40
            other_params,
40
            value,
40
        },
40
    ))
920
}
/// Parse a SEQUENCE property.
///
/// RFC 5545, section 3.8.7.4
699
pub fn prop_sequence<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], SequenceProperty<'a>, E>
699
where
699
    E: ParseError<&'a [u8]> + From<Error<'a>>,
699
{
699
    let (input, (_, (other_params, _, value, _))) = (
699
        tag_no_case("SEQUENCE"),
699
        cut((
699
            other_params,
699
            char(':'),
699
            prop_value_integer.map(|v| v as u32),
699
            tag("\r\n"),
699
        )),
699
    )
699
        .parse(input)?;
20
    Ok((
20
        input,
20
        SequenceProperty {
20
            other_params,
20
            value,
20
        },
20
    ))
699
}
/// Parse a REQUEST-STATUS property.
///
/// RFC 5545, section 3.8.8.3
331
pub fn prop_request_status<'a, E>(
331
    input: &'a [u8],
331
) -> IResult<&'a [u8], RequestStatusProperty<'a>, E>
331
where
331
    E: ParseError<&'a [u8]>
331
        + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
331
        + From<Error<'a>>,
331
{
12
    fn status_code<'a, E>(input: &'a [u8]) -> IResult<&'a [u8], Vec<u32>, E>
12
    where
12
        E: ParseError<&'a [u8]>
12
            + nom::error::FromExternalError<&'a [u8], nom::Err<E>>
12
            + From<Error<'a>>,
12
    {
12
        let (input, (num, mut nums)) = (
12
            map_res(
12
                verify(take_while1(AsChar::is_dec_digit), |v: &[u8]| v.len() == 1),
12
                |v| read_int::<E, u32>(v),
12
            ),
12
            fold_many_m_n(
12
                1,
12
                2,
12
                map_res((char('.'), take_while1(AsChar::is_dec_digit)), |(_, v)| {
12
                    read_int::<E, u32>(v)
12
                }),
12
                Vec::new,
12
                |mut acc, item| {
12
                    acc.push(item);
12
                    acc
12
                },
12
            ),
12
        )
12
            .parse(input)?;
12
        nums.insert(0, num);
12
        Ok((input, nums))
12
    }
331
    let (input, (_, (params, _, status_code, _, status_description, extra_data, _))) = (
331
        tag_no_case("REQUEST-STATUS"),
331
        cut((
331
            property_params,
331
            char(':'),
331
            status_code,
331
            char(';'),
331
            prop_value_text,
331
            opt((char(';'), prop_value_text).map(|(_, v)| v)),
331
            tag("\r\n"),
331
        )),
331
    )
331
        .parse(input)?;
12
    Ok((
12
        input,
12
        RequestStatusProperty {
12
            params,
12
            status_code,
12
            status_description,
12
            exception_data: extra_data,
12
        },
12
    ))
331
}
#[cfg(test)]
mod tests {
    use super::*;
    use crate::common::FreeBusyTimeType;
    use crate::common::RecurFreq;
    use crate::common::{
        LanguageTag, ParticipationStatusUnknown, Range, Role, TriggerRelationship, Value,
    };
    use crate::parser::types::ParamValue;
    use crate::parser::types::RecurRulePart;
    use crate::parser::types::{Authority, Host, Uri};
    use crate::parser::types::{Date, DateTime, Duration, Period, PeriodEnd, Time, UtcOffset};
    use crate::test_utils::check_rem;
    use base64::Engine;
    #[test]
2
    fn attach_uri() {
2
        let (rem, prop) =
2
            prop_attach::<Error>(b"ATTACH:CID:jsmith.part3.960817T083000.xyzMail@example.com\r\n;")
2
                .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            AttachProperty {
2
                params: vec![],
2
                value: AttachValue::Uri(b"CID:jsmith.part3.960817T083000.xyzMail@example.com"),
2
            }
2
        );
2
    }
    #[test]
2
    fn attach_binary() {
2
        let (rem, prop) =
2
            prop_attach::<Error>(b"ATTACH;VALUE=BINARY;ENCODING=BASE64:dGVzdA==\r\n;").unwrap();
2
        check_rem(rem, 1);
2

            
2
        let r = base64::prelude::BASE64_STANDARD.encode("test");
2

            
2
        assert_eq!(
2
            prop,
2
            AttachProperty {
2
                params: vec![
2
                    ParamValue::ValueType {
2
                        value: Value::Binary
2
                    },
2
                    ParamValue::Encoding {
2
                        encoding: Encoding::Base64,
2
                    },
2
                ],
2
                value: AttachValue::Binary(r.as_bytes()),
2
            }
2
        );
2
    }
    #[test]
2
    fn categories() {
2
        let (rem, prop) =
2
            prop_categories::<Error>(b"CATEGORIES:APPOINTMENT,EDUCATION\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            CategoriesProperty {
2
                params: vec![],
2
                value: vec![b"APPOINTMENT".to_vec(), b"EDUCATION".to_vec()],
2
            }
2
        );
2
    }
    #[test]
2
    fn classification_public() {
2
        let (rem, prop) = prop_classification::<Error>(b"CLASS:PUBLIC\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            ClassificationProperty {
2
                other_params: vec![],
2
                value: Classification::Public,
2
            }
2
        );
2
    }
    #[test]
2
    fn comment() {
2
        let (rem, prop) = prop_comment::<Error>(b"COMMENT:The meeting really needs to include both ourselves and the customer. We can't hold this meeting without them. As a matter of fact\\, the venue for the meeting ought to be at their site. - - John\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            CommentProperty {
2
                params: vec![],
2
                value: b"The meeting really needs to include both ourselves and the customer. We can't hold this meeting without them. As a matter of fact, the venue for the meeting ought to be at their site. - - John".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn description() {
2
        let (rem, prop) = prop_description::<Error>(b"DESCRIPTION:Meeting to provide technical review for \"Phoenix\"\r\n  design.\\nHappy Face Conference Room. Phoenix design team\r\n  MUST attend this meeting.\\nRSVP to team leader.\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DescriptionProperty {
2
                params: vec![],
2
                value: br#"Meeting to provide technical review for "Phoenix" design.
2
Happy Face Conference Room. Phoenix design team MUST attend this meeting.
2
RSVP to team leader."#
2
                    .to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn geographic_position() {
2
        let (rem, prop) =
2
            prop_geographic_position::<Error>(b"GEO:37.386013;-122.082932\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            GeographicPositionProperty {
2
                other_params: vec![],
2
                latitude: 37.386013,
2
                longitude: -122.082932,
2
            }
2
        );
2
    }
    #[test]
2
    fn location() {
2
        let (rem, prop) =
2
            prop_location::<Error>(b"LOCATION:Conference Room - F123\\, Bldg. 002\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            LocationProperty {
2
                params: vec![],
2
                value: b"Conference Room - F123, Bldg. 002".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn location_with_params() {
2
        let (rem, prop) = prop_location::<Error>(b"LOCATION;ALTREP=\"http://xyzcorp.com/conf-rooms/f123.vcf\":\r\n Conference Room - F123\\, Bldg. 002\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            LocationProperty {
2
                params: vec![ParamValue::AltRep {
2
                    uri: b"http://xyzcorp.com/conf-rooms/f123.vcf",
2
                },],
2
                value: b"Conference Room - F123, Bldg. 002".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn percent_complete() {
2
        let (rem, prop) = prop_percent_complete::<Error>(b"PERCENT-COMPLETE:39\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            PercentCompleteProperty {
2
                other_params: vec![],
2
                value: 39,
2
            }
2
        );
2
    }
    #[test]
2
    fn priority() {
2
        let (rem, prop) = prop_priority::<Error>(b"PRIORITY:1\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            PriorityProperty {
2
                other_params: vec![],
2
                value: 1,
2
            }
2
        );
2
    }
    #[test]
2
    fn resources() {
2
        let (rem, prop) = prop_resources::<Error>(b"RESOURCES:EASEL,PROJECTOR,VCR\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            ResourcesProperty {
2
                params: vec![],
2
                value: vec![b"EASEL".to_vec(), b"PROJECTOR".to_vec(), b"VCR".to_vec()],
2
            }
2
        );
2
    }
    #[test]
2
    fn status() {
2
        let (rem, prop) = prop_status::<Error>(b"STATUS:TENTATIVE\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            StatusProperty {
2
                other_params: vec![],
2
                value: Status::Tentative,
2
            }
2
        );
2
    }
    #[test]
2
    fn summary() {
2
        let (rem, prop) = prop_summary::<Error>(b"SUMMARY:Department Party\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            SummaryProperty {
2
                params: vec![],
2
                value: b"Department Party".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn date_time_completed() {
2
        let (rem, prop) =
2
            prop_date_time_completed::<Error>(b"COMPLETED:19960401T150000Z\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeCompletedProperty {
2
                other_params: vec![],
2
                value: DateTime {
2
                    date: Date {
2
                        year: 1996,
2
                        month: 4,
2
                        day: 1,
2
                    },
2
                    time: Time {
2
                        hour: 15,
2
                        minute: 0,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                },
2
            }
2
        );
2
    }
    #[test]
2
    fn date_time_end_date() {
2
        let (rem, prop) = prop_date_time_end::<Error>(b"DTEND;VALUE=DATE:19980704\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeEndProperty {
2
                params: vec![ParamValue::ValueType { value: Value::Date },],
2
                value: DateOrDateTime::Date(Date {
2
                    year: 1998,
2
                    month: 7,
2
                    day: 4,
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn date_time_end_datetime() {
2
        let (rem, prop) = prop_date_time_end::<Error>(b"DTEND:19960401T150000Z\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeEndProperty {
2
                params: vec![],
2
                value: DateOrDateTime::DateTime(DateTime {
2
                    date: Date {
2
                        year: 1996,
2
                        month: 4,
2
                        day: 1,
2
                    },
2
                    time: Time {
2
                        hour: 15,
2
                        minute: 0,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn date_time_due_date() {
2
        let (rem, prop) = prop_date_time_due::<Error>(b"DUE;VALUE=DATE:19980401\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeDueProperty {
2
                params: vec![ParamValue::ValueType { value: Value::Date },],
2
                value: DateOrDateTime::Date(Date {
2
                    year: 1998,
2
                    month: 4,
2
                    day: 1,
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn date_time_due_datetime() {
2
        let (rem, prop) = prop_date_time_due::<Error>(b"DUE:19980430T000000Z\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeDueProperty {
2
                params: vec![],
2
                value: DateOrDateTime::DateTime(DateTime {
2
                    date: Date {
2
                        year: 1998,
2
                        month: 4,
2
                        day: 30,
2
                    },
2
                    time: Time {
2
                        hour: 0,
2
                        minute: 0,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn date_time_start_date() {
2
        let (rem, prop) = prop_date_time_start::<Error>(b"DTSTART:19980118\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeStartProperty {
2
                params: vec![],
2
                value: DateOrDateTime::Date(Date {
2
                    year: 1998,
2
                    month: 1,
2
                    day: 18,
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn date_time_start_datetime() {
2
        let (rem, prop) = prop_date_time_start::<Error>(b"DTSTART:19980118T073000Z\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeStartProperty {
2
                params: vec![],
2
                value: DateOrDateTime::DateTime(DateTime {
2
                    date: Date {
2
                        year: 1998,
2
                        month: 1,
2
                        day: 18,
2
                    },
2
                    time: Time {
2
                        hour: 7,
2
                        minute: 30,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn duration() {
2
        let (rem, prop) = prop_duration::<Error>(b"DURATION:PT1H0M0S\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DurationProperty {
2
                other_params: vec![],
2
                value: Duration {
2
                    sign: 1,
2
                    hours: Some(1),
2
                    minutes: Some(0),
2
                    seconds: Some(0),
2
                    ..Default::default()
2
                },
2
            }
2
        );
2
    }
    #[test]
2
    fn free_busy() {
2
        let (rem, prop) = prop_free_busy_time::<Error>(
2
            b"FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:19970308T160000Z/PT8H30M\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            FreeBusyTimeProperty {
2
                params: vec![ParamValue::FreeBusyTimeType {
2
                    fb_type: FreeBusyTimeType::BusyUnavailable,
2
                },],
2
                value: vec![Period {
2
                    start: DateTime {
2
                        date: Date {
2
                            year: 1997,
2
                            month: 3,
2
                            day: 8,
2
                        },
2
                        time: Time {
2
                            hour: 16,
2
                            minute: 0,
2
                            second: 0,
2
                            is_utc: true,
2
                        },
2
                    },
2
                    end: PeriodEnd::Duration(Duration {
2
                        sign: 1,
2
                        hours: Some(8),
2
                        minutes: Some(30),
2
                        ..Default::default()
2
                    }),
2
                }],
2
            }
2
        );
2
    }
    #[test]
2
    fn free_busy_multiple() {
2
        let (rem, prop) = prop_free_busy_time::<Error>(
2
            b"FREEBUSY;FBTYPE=FREE:19970308T160000Z/PT3H,19970308T200000Z/PT1H\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            FreeBusyTimeProperty {
2
                params: vec![ParamValue::FreeBusyTimeType {
2
                    fb_type: FreeBusyTimeType::Free,
2
                },],
2
                value: vec![
2
                    Period {
2
                        start: DateTime {
2
                            date: Date {
2
                                year: 1997,
2
                                month: 3,
2
                                day: 8,
2
                            },
2
                            time: Time {
2
                                hour: 16,
2
                                minute: 0,
2
                                second: 0,
2
                                is_utc: true,
2
                            },
2
                        },
2
                        end: PeriodEnd::Duration(Duration {
2
                            sign: 1,
2
                            hours: Some(3),
2
                            ..Default::default()
2
                        }),
2
                    },
2
                    Period {
2
                        start: DateTime {
2
                            date: Date {
2
                                year: 1997,
2
                                month: 3,
2
                                day: 8,
2
                            },
2
                            time: Time {
2
                                hour: 20,
2
                                minute: 0,
2
                                second: 0,
2
                                is_utc: true,
2
                            },
2
                        },
2
                        end: PeriodEnd::Duration(Duration {
2
                            sign: 1,
2
                            hours: Some(1),
2
                            ..Default::default()
2
                        }),
2
                    },
2
                ],
2
            }
2
        );
2
    }
    #[test]
2
    fn transp_opaque() {
2
        let (rem, prop) = prop_time_transparency::<Error>(b"TRANSP:OPAQUE\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeTransparencyProperty {
2
                other_params: vec![],
2
                value: TimeTransparency::Opaque,
2
            }
2
        );
2
    }
    #[test]
2
    fn transp_transparent() {
2
        let (rem, prop) = prop_time_transparency::<Error>(b"TRANSP:TRANSPARENT\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeTransparencyProperty {
2
                other_params: vec![],
2
                value: TimeTransparency::Transparent,
2
            }
2
        );
2
    }
    #[test]
2
    fn time_zone_id() {
2
        let (rem, prop) = prop_time_zone_id::<Error>(b"TZID:America/New_York\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeZoneIdProperty {
2
                other_params: vec![],
2
                unique_registry_id: false,
2
                value: b"America/New_York".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn time_zone_id_custom() {
2
        let (rem, prop) =
2
            prop_time_zone_id::<Error>(b"TZID:/example.org/America/New_York\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeZoneIdProperty {
2
                other_params: vec![],
2
                unique_registry_id: true,
2
                value: b"example.org/America/New_York".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn time_zone_name() {
2
        let (rem, prop) = prop_time_zone_name::<Error>(b"TZNAME:EST\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeZoneNameProperty {
2
                params: vec![],
2
                value: b"EST".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn time_zone_name_with_params() {
2
        let (rem, prop) = prop_time_zone_name::<Error>(b"TZNAME;LANGUAGE=fr-CA:HNE\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeZoneNameProperty {
2
                params: vec![ParamValue::Language {
2
                    language: LanguageTag {
2
                        language: "fr".to_string(),
2
                        region: Some("CA".to_string()),
2
                        ..Default::default()
2
                    },
2
                },],
2
                value: b"HNE".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn time_zone_offset_from() {
2
        let (rem, prop) = prop_time_zone_offset_from::<Error>(b"TZOFFSETFROM:-0500\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeZoneOffsetProperty {
2
                other_params: vec![],
2
                value: UtcOffset {
2
                    sign: -1,
2
                    hours: 5,
2
                    minutes: 0,
2
                    seconds: None,
2
                },
2
            }
2
        );
2
    }
    #[test]
2
    fn time_zone_offset_to() {
2
        let (rem, prop) = prop_time_zone_offset_to::<Error>(b"TZOFFSETTO:+1245\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeZoneOffsetProperty {
2
                other_params: vec![],
2
                value: UtcOffset {
2
                    sign: 1,
2
                    hours: 12,
2
                    minutes: 45,
2
                    seconds: None,
2
                },
2
            }
2
        );
2
    }
    #[test]
2
    fn time_zone_url() {
2
        let (rem, prop) = prop_time_zone_url::<Error>(
2
            b"TZURL:http://timezones.example.org/tz/America-Los_Angeles.ics\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TimeZoneUrlProperty {
2
                other_params: vec![],
2
                value: b"http://timezones.example.org/tz/America-Los_Angeles.ics",
2
            }
2
        );
2
    }
    #[test]
2
    fn attendee() {
2
        let (rem, prop) = prop_attendee::<Error>(b"ATTENDEE;ROLE=REQ-PARTICIPANT;DELEGATED-FROM=\"mailto:bob@example.com\";PARTSTAT=ACCEPTED;CN=Jane Doe:mailto:jdoe@example.com\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            AttendeeProperty {
2
                params: vec![
2
                    ParamValue::Role {
2
                        role: Role::RequiredParticipant,
2
                    },
2
                    ParamValue::DelegatedFrom {
2
                        delegators: vec![b"mailto:bob@example.com"],
2
                    },
2
                    ParamValue::ParticipationStatus {
2
                        status: ParticipationStatusUnknown::Accepted,
2
                    },
2
                    ParamValue::CommonName {
2
                        name: "Jane Doe".to_string(),
2
                    },
2
                ],
2
                value: b"mailto:jdoe@example.com",
2
            }
2
        );
2
    }
    #[test]
2
    fn contact() {
2
        let (rem, prop) = prop_contact::<Error>(
2
            b"CONTACT:Jim Dolittle\\, ABC Industries\\, +1-919-555-1234\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            ContactProperty {
2
                params: vec![],
2
                value: b"Jim Dolittle, ABC Industries, +1-919-555-1234".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn contact_altrep() {
2
        let (rem, prop) = prop_contact::<Error>(b"CONTACT;ALTREP=\"ldap://example.com:6666/o=ABC%20Industries,c=US???(cn=Jim%20Dolittle)\":Jim Dolittle\\, ABC Industries\\, +1-919-555-1234\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            ContactProperty {
2
                params: vec![ParamValue::AltRep {
2
                    uri: b"ldap://example.com:6666/o=ABC%20Industries,c=US???(cn=Jim%20Dolittle)",
2
                },],
2
                value: b"Jim Dolittle, ABC Industries, +1-919-555-1234".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn organizer() {
2
        let (rem, prop) =
2
            prop_organizer::<Error>(b"ORGANIZER;CN=John Smith:mailto:jsmith@example.com\r\n;")
2
                .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            OrganizerProperty {
2
                params: vec![ParamValue::CommonName {
2
                    name: "John Smith".to_string(),
2
                },],
2
                value: b"mailto:jsmith@example.com",
2
            }
2
        );
2
    }
    #[test]
2
    fn organizer_with_params() {
2
        let (rem, prop) = prop_organizer::<Error>(b"ORGANIZER;CN=JohnSmith;DIR=\"ldap://example.com:6666/o=DC%20Associates,c=US???(cn=John%20Smith)\":mailto:jsmith@example.com\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            OrganizerProperty {
2
                params: vec![
2
                    ParamValue::CommonName {
2
                        name: "JohnSmith".to_string(),
2
                    },
2
                    ParamValue::DirectoryEntryReference {
2
                        uri: b"ldap://example.com:6666/o=DC%20Associates,c=US???(cn=John%20Smith)",
2
                    },
2
                ],
2
                value: b"mailto:jsmith@example.com",
2
            }
2
        );
2
    }
    #[test]
2
    fn organizer_with_sent_by_param() {
2
        let (rem, prop) = prop_organizer::<Error>(
2
            b"ORGANIZER;SENT-BY=\"mailto:jane_doe@example.com\":mailto:jsmith@example.com\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            OrganizerProperty {
2
                params: vec![ParamValue::SentBy {
2
                    address: b"mailto:jane_doe@example.com",
2
                },],
2
                value: b"mailto:jsmith@example.com",
2
            }
2
        );
2
    }
    #[test]
2
    fn recurrence_id_date() {
2
        let (rem, prop) =
2
            prop_recurrence_id::<Error>(b"RECURRENCE-ID;VALUE=DATE:19960401\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RecurrenceIdProperty {
2
                params: vec![ParamValue::ValueType { value: Value::Date },],
2
                value: DateOrDateTime::Date(Date {
2
                    year: 1996,
2
                    month: 4,
2
                    day: 1,
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn recurrence_id_datetime() {
2
        let (rem, prop) =
2
            prop_recurrence_id::<Error>(b"RECURRENCE-ID;RANGE=THISANDFUTURE:19960120T120000Z\r\n;")
2
                .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RecurrenceIdProperty {
2
                params: vec![ParamValue::Range {
2
                    range: Range::ThisAndFuture,
2
                },],
2
                value: DateOrDateTime::DateTime(DateTime {
2
                    date: Date {
2
                        year: 1996,
2
                        month: 1,
2
                        day: 20,
2
                    },
2
                    time: Time {
2
                        hour: 12,
2
                        minute: 0,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn related_to() {
2
        let (rem, prop) = prop_related_to::<Error>(
2
            b"RELATED-TO:jsmith.part7.19960817T083000.xyzMail@example.com\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RelatedToProperty {
2
                params: vec![],
2
                value: b"jsmith.part7.19960817T083000.xyzMail@example.com".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn url() {
2
        let (rem, prop) =
2
            prop_url::<Error>(b"URL:http://example.com/pub/calendars/jsmith/mytime.ics\r\n;")
2
                .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            UrlProperty {
2
                other_params: vec![],
2
                value: Uri {
2
                    scheme: b"http",
2
                    authority: Some(Authority {
2
                        user_info: None,
2
                        host: Host::RegName(b"example.com".to_vec()),
2
                        port: None,
2
                    }),
2
                    path: b"/pub/calendars/jsmith/mytime.ics".to_vec(),
2
                    query: None,
2
                    fragment: None,
2
                },
2
            }
2
        );
2
    }
    #[test]
2
    fn unique_identifier() {
2
        let (rem, prop) = prop_unique_identifier::<Error>(
2
            b"UID:19960401T080045Z-4000F192713-0052@example.com\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            UniqueIdentifierProperty {
2
                other_params: vec![],
2
                value: b"19960401T080045Z-4000F192713-0052@example.com".to_vec(),
2
            }
2
        );
2
    }
    #[test]
2
    fn exception_date_times() {
2
        let (rem, prop) = prop_exception_date_times::<Error>(
2
            b"EXDATE:19960402T010000Z,19960403T010000Z,19960404T010000Z\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            ExceptionDateTimesProperty {
2
                params: vec![],
2
                value: vec![
2
                    DateOrDateTime::DateTime(DateTime {
2
                        date: Date {
2
                            year: 1996,
2
                            month: 4,
2
                            day: 2,
2
                        },
2
                        time: Time {
2
                            hour: 1,
2
                            minute: 0,
2
                            second: 0,
2
                            is_utc: true,
2
                        },
2
                    }),
2
                    DateOrDateTime::DateTime(DateTime {
2
                        date: Date {
2
                            year: 1996,
2
                            month: 4,
2
                            day: 3,
2
                        },
2
                        time: Time {
2
                            hour: 1,
2
                            minute: 0,
2
                            second: 0,
2
                            is_utc: true,
2
                        },
2
                    }),
2
                    DateOrDateTime::DateTime(DateTime {
2
                        date: Date {
2
                            year: 1996,
2
                            month: 4,
2
                            day: 4,
2
                        },
2
                        time: Time {
2
                            hour: 1,
2
                            minute: 0,
2
                            second: 0,
2
                            is_utc: true,
2
                        },
2
                    }),
2
                ],
2
            }
2
        );
2
    }
    #[test]
2
    fn recurrence_date_times_datetime() {
2
        let (rem, prop) = prop_recurrence_date_times::<Error>(
2
            b"RDATE;TZID=America/New_York:19970714T083000\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RecurrenceDateTimesProperty {
2
                params: vec![ParamValue::TimeZoneId {
2
                    tz_id: "America/New_York".to_string(),
2
                    unique: false,
2
                },],
2
                value: vec![DateOrDateTimeOrPeriod::DateTime(DateTime {
2
                    date: Date {
2
                        year: 1997,
2
                        month: 7,
2
                        day: 14,
2
                    },
2
                    time: Time {
2
                        hour: 8,
2
                        minute: 30,
2
                        second: 0,
2
                        is_utc: false,
2
                    },
2
                }),],
2
            }
2
        );
2
    }
    #[test]
2
    fn recurrence_date_times_periods() {
2
        let (rem, prop) = prop_recurrence_date_times::<Error>(
2
            b"RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,19960404T010000Z/PT3H\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RecurrenceDateTimesProperty {
2
                params: vec![ParamValue::ValueType {
2
                    value: Value::Period
2
                },],
2
                value: vec![
2
                    DateOrDateTimeOrPeriod::Period(Period {
2
                        start: DateTime {
2
                            date: Date {
2
                                year: 1996,
2
                                month: 4,
2
                                day: 3,
2
                            },
2
                            time: Time {
2
                                hour: 2,
2
                                minute: 0,
2
                                second: 0,
2
                                is_utc: true,
2
                            },
2
                        },
2
                        end: PeriodEnd::DateTime(DateTime {
2
                            date: Date {
2
                                year: 1996,
2
                                month: 4,
2
                                day: 3,
2
                            },
2
                            time: Time {
2
                                hour: 4,
2
                                minute: 0,
2
                                second: 0,
2
                                is_utc: true,
2
                            },
2
                        }),
2
                    }),
2
                    DateOrDateTimeOrPeriod::Period(Period {
2
                        start: DateTime {
2
                            date: Date {
2
                                year: 1996,
2
                                month: 4,
2
                                day: 4,
2
                            },
2
                            time: Time {
2
                                hour: 1,
2
                                minute: 0,
2
                                second: 0,
2
                                is_utc: true,
2
                            },
2
                        },
2
                        end: PeriodEnd::Duration(Duration {
2
                            sign: 1,
2
                            hours: Some(3),
2
                            ..Default::default()
2
                        }),
2
                    }),
2
                ],
2
            }
2
        );
2
    }
    #[test]
2
    fn recurrence_date_times_dates() {
2
        let (rem, prop) = prop_recurrence_date_times::<Error>(
2
            b"RDATE;VALUE=DATE:19970101,19970120,19970217,19970421\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RecurrenceDateTimesProperty {
2
                params: vec![ParamValue::ValueType { value: Value::Date },],
2
                value: vec![
2
                    DateOrDateTimeOrPeriod::Date(Date {
2
                        year: 1997,
2
                        month: 1,
2
                        day: 1,
2
                    }),
2
                    DateOrDateTimeOrPeriod::Date(Date {
2
                        year: 1997,
2
                        month: 1,
2
                        day: 20,
2
                    }),
2
                    DateOrDateTimeOrPeriod::Date(Date {
2
                        year: 1997,
2
                        month: 2,
2
                        day: 17,
2
                    }),
2
                    DateOrDateTimeOrPeriod::Date(Date {
2
                        year: 1997,
2
                        month: 4,
2
                        day: 21,
2
                    }),
2
                ],
2
            }
2
        );
2
    }
    #[test]
2
    fn recurrence_rule() {
2
        let (rem, prop) = prop_recurrence_rule::<Error>(b"RRULE:FREQ=DAILY;COUNT=10\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RecurrenceRuleProperty {
2
                other_params: vec![],
2
                value: vec![
2
                    RecurRulePart::Freq(RecurFreq::Daily),
2
                    RecurRulePart::Count(10),
2
                ],
2
            }
2
        );
2
    }
    #[test]
2
    fn created() {
2
        let (rem, prop) =
2
            prop_date_time_created::<Error>(b"CREATED:19980118T230000Z\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeCreatedProperty {
2
                other_params: vec![],
2
                value: DateTime {
2
                    date: Date {
2
                        year: 1998,
2
                        month: 1,
2
                        day: 18,
2
                    },
2
                    time: Time {
2
                        hour: 23,
2
                        minute: 0,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                },
2
            }
2
        );
2
    }
    #[test]
2
    fn action() {
2
        let (rem, prop) = prop_action::<Error>(b"ACTION:DISPLAY\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            ActionProperty {
2
                other_params: vec![],
2
                value: Action::Display,
2
            }
2
        );
2
    }
    #[test]
2
    fn repeat() {
2
        let (rem, prop) = prop_repeat::<Error>(b"REPEAT:4\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RepeatProperty {
2
                other_params: vec![],
2
                value: 4,
2
            }
2
        );
2
    }
    #[test]
2
    fn trigger_duration() {
2
        let (rem, prop) = prop_trigger::<Error>(b"TRIGGER:-PT15M\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TriggerProperty {
2
                params: vec![],
2
                value: DurationOrDateTime::Duration(Duration {
2
                    sign: -1,
2
                    minutes: Some(15),
2
                    ..Default::default()
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn trigger_duration_related_end() {
2
        let (rem, prop) = prop_trigger::<Error>(b"TRIGGER;RELATED=END:PT5M\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TriggerProperty {
2
                params: vec![ParamValue::Related {
2
                    related: TriggerRelationship::End,
2
                },],
2
                value: DurationOrDateTime::Duration(Duration {
2
                    sign: 1,
2
                    minutes: Some(5),
2
                    ..Default::default()
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn trigger_date_time() {
2
        let (rem, prop) =
2
            prop_trigger::<Error>(b"TRIGGER;VALUE=DATE-TIME:19980101T050000Z\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            TriggerProperty {
2
                params: vec![ParamValue::ValueType {
2
                    value: Value::DateTime,
2
                },],
2
                value: DurationOrDateTime::DateTime(DateTime {
2
                    date: Date {
2
                        year: 1998,
2
                        month: 1,
2
                        day: 1,
2
                    },
2
                    time: Time {
2
                        hour: 5,
2
                        minute: 0,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                }),
2
            }
2
        );
2
    }
    #[test]
2
    fn date_time_stamp() {
2
        let (rem, prop) =
2
            prop_date_time_created::<Error>(b"CREATED:19960329T133000Z\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            DateTimeCreatedProperty {
2
                other_params: vec![],
2
                value: DateTime {
2
                    date: Date {
2
                        year: 1996,
2
                        month: 3,
2
                        day: 29,
2
                    },
2
                    time: Time {
2
                        hour: 13,
2
                        minute: 30,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                },
2
            }
2
        );
2
    }
    #[test]
2
    fn last_modified() {
2
        let (rem, prop) =
2
            prop_last_modified::<Error>(b"LAST-MODIFIED:19960817T133000Z\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            LastModifiedProperty {
2
                other_params: vec![],
2
                value: DateTime {
2
                    date: Date {
2
                        year: 1996,
2
                        month: 8,
2
                        day: 17,
2
                    },
2
                    time: Time {
2
                        hour: 13,
2
                        minute: 30,
2
                        second: 0,
2
                        is_utc: true,
2
                    },
2
                },
2
            }
2
        );
2
    }
    #[test]
2
    fn sequence() {
2
        let (rem, prop) = prop_sequence::<Error>(b"SEQUENCE:2\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            SequenceProperty {
2
                other_params: vec![],
2
                value: 2,
2
            }
2
        );
2
    }
    #[test]
2
    fn request_status() {
2
        let (rem, prop) = prop_request_status::<Error>(b"REQUEST-STATUS:2.0;Success\r\n;").unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RequestStatusProperty {
2
                params: vec![],
2
                status_code: vec![2, 0],
2
                status_description: b"Success".to_vec(),
2
                exception_data: None,
2
            }
2
        );
2
    }
    #[test]
2
    fn request_status_rejected() {
2
        let (rem, prop) = prop_request_status::<Error>(
2
            b"REQUEST-STATUS:3.1;Invalid property value;DTSTART:96-Apr-01\r\n;",
2
        )
2
        .unwrap();
2
        check_rem(rem, 1);
2
        assert_eq!(
2
            prop,
2
            RequestStatusProperty {
2
                params: vec![],
2
                status_code: vec![3, 1],
2
                status_description: b"Invalid property value".to_vec(),
2
                exception_data: Some(b"DTSTART:96-Apr-01".to_vec()),
2
            }
2
        );
2
    }
}