1
use crate::common::LanguageTag;
2
use crate::serialize::WriteModel;
3
use std::io::Write;
4
use std::ops::Add;
5

            
6
impl WriteModel for (time::Date, time::Time, bool) {
7
222
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
8
222
        self.0.write_model(writer)?;
9
222
        writer.write_all(b"T")?;
10
222
        self.1.write_model(writer)?;
11
222
        if self.2 {
12
158
            writer.write_all(b"Z")?;
13
64
        }
14

            
15
222
        Ok(())
16
222
    }
17
}
18

            
19
impl WriteModel for (time::Date, Option<time::Time>, bool) {
20
208
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
21
208
        match self.1 {
22
198
            Some(time) => {
23
198
                (self.0, time, self.2).write_model(writer)?;
24
            }
25
            None => {
26
10
                self.0.write_model(writer)?;
27
            }
28
        }
29

            
30
208
        Ok(())
31
208
    }
32
}
33

            
34
impl WriteModel for time::Date {
35
232
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
36
232
        let year = self.year();
37
232
        write!(writer, "{:0>4}", year)?;
38
232
        write!(writer, "{:0>2}", self.month() as u8)?;
39
232
        write!(writer, "{:0>2}", self.day())?;
40

            
41
232
        Ok(())
42
232
    }
43
}
44

            
45
impl WriteModel for time::Time {
46
222
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
47
222
        match self.hour() {
48
148
            h @ 10..=23 => {
49
148
                write!(writer, "{}", h)?;
50
            }
51
74
            h => {
52
74
                write!(writer, "0{}", h)?;
53
            }
54
        }
55

            
56
222
        match self.minute() {
57
28
            m @ 10..=59 => {
58
28
                write!(writer, "{}", m)?;
59
            }
60
194
            m => {
61
194
                write!(writer, "0{}", m)?;
62
            }
63
        }
64

            
65
222
        match self.second() {
66
10
            s @ 10..=60 => {
67
10
                write!(writer, "{}", s)?;
68
            }
69
212
            s => {
70
212
                write!(writer, "0{}", s)?;
71
            }
72
        }
73

            
74
222
        Ok(())
75
222
    }
76
}
77

            
78
impl WriteModel for crate::common::CalendarDateTime {
79
208
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
80
208
        (*self.date(), self.time_opt().cloned(), self.is_utc()).write_model(writer)
81
208
    }
82
}
83

            
84
impl WriteModel for crate::common::Value {
85
18
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
86
18
        use crate::common::Value;
87
18

            
88
18
        match self {
89
            Value::Binary => {
90
2
                writer.write_all(b"BINARY")?;
91
            }
92
            Value::Boolean => {
93
                writer.write_all(b"BOOLEAN")?;
94
            }
95
            Value::CalendarAddress => {
96
                writer.write_all(b"CALENDAR-ADDRESS")?;
97
            }
98
            Value::Date => {
99
10
                writer.write_all(b"DATE")?;
100
            }
101
            Value::DateTime => {
102
6
                writer.write_all(b"DATE-TIME")?;
103
            }
104
            Value::Duration => {
105
                writer.write_all(b"DURATION")?;
106
            }
107
            Value::Float => {
108
                writer.write_all(b"FLOAT")?;
109
            }
110
            Value::Integer => {
111
                writer.write_all(b"INTEGER")?;
112
            }
113
            Value::Period => {
114
                writer.write_all(b"PERIOD")?;
115
            }
116
            Value::Recurrence => {
117
                writer.write_all(b"RECUR")?;
118
            }
119
            Value::Text => {
120
                writer.write_all(b"TEXT")?;
121
            }
122
            Value::Time => {
123
                writer.write_all(b"TIME")?;
124
            }
125
            Value::Uri => {
126
                writer.write_all(b"URI")?;
127
            }
128
            Value::UtcOffset => {
129
                writer.write_all(b"UTC-OFFSET")?;
130
            }
131
            Value::XName(name) => {
132
                write!(writer, "{}", name)?;
133
            }
134
            Value::IanaToken(token) => {
135
                write!(writer, "{}", token)?;
136
            }
137
        }
138

            
139
18
        Ok(())
140
18
    }
141
}
142

            
143
impl WriteModel for LanguageTag {
144
70
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
145
70
        writer.write_all(self.language.as_bytes())?;
146
70
        if let Some(ext_lang) = &self.ext_lang {
147
66
            writer.write_all(b"-")?;
148
66
            writer.write_all(ext_lang.as_bytes())?;
149
4
        }
150
70
        if let Some(script) = &self.script {
151
66
            writer.write_all(b"-")?;
152
66
            writer.write_all(script.as_bytes())?;
153
4
        }
154
70
        if let Some(region) = &self.region {
155
70
            writer.write_all(b"-")?;
156
70
            writer.write_all(region.as_bytes())?;
157
        }
158
202
        for variant in &self.variants {
159
132
            writer.write_all(b"-")?;
160
132
            writer.write_all(variant.as_bytes())?;
161
        }
162
202
        for extension in &self.extensions {
163
132
            writer.write_all(b"-")?;
164
132
            writer.write_all(extension.as_bytes())?;
165
        }
166
70
        if let Some(private_use) = &self.private_use {
167
66
            writer.write_all(b"-")?;
168
66
            writer.write_all(private_use.as_bytes())?;
169
4
        }
170
70
        Ok(())
171
70
    }
172
}
173

            
174
impl WriteModel for crate::common::Range {
175
6
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
176
6
        use crate::common::Range;
177
6

            
178
6
        match self {
179
6
            Range::ThisAndFuture => {
180
6
                writer.write_all(b"THISANDFUTURE")?;
181
            }
182
        }
183

            
184
6
        Ok(())
185
6
    }
186
}
187

            
188
impl WriteModel for crate::common::Encoding {
189
12
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
190
12
        use crate::common::Encoding;
191
12

            
192
12
        match self {
193
            Encoding::EightBit => {
194
6
                writer.write_all(b"8BIT")?;
195
            }
196
            Encoding::Base64 => {
197
6
                writer.write_all(b"BASE64")?;
198
            }
199
        }
200

            
201
12
        Ok(())
202
12
    }
203
}
204

            
205
impl WriteModel for crate::common::CalendarUserType {
206
6
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
207
6
        use crate::common::CalendarUserType;
208
6

            
209
6
        match self {
210
            CalendarUserType::Individual => {
211
                writer.write_all(b"INDIVIDUAL")?;
212
            }
213
            CalendarUserType::Group => {
214
                writer.write_all(b"GROUP")?;
215
            }
216
            CalendarUserType::Resource => {
217
                writer.write_all(b"RESOURCE")?;
218
            }
219
            CalendarUserType::Room => {
220
6
                writer.write_all(b"ROOM")?;
221
            }
222
            CalendarUserType::Unknown => {
223
                writer.write_all(b"UNKNOWN")?;
224
            }
225
            CalendarUserType::XName(name) => {
226
                writer.write_all(name.as_bytes())?;
227
            }
228
            CalendarUserType::IanaToken(token) => {
229
                writer.write_all(token.as_bytes())?;
230
            }
231
        }
232

            
233
6
        Ok(())
234
6
    }
235
}
236

            
237
impl WriteModel for crate::common::Role {
238
6
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
239
6
        use crate::common::Role;
240
6

            
241
6
        match self {
242
            Role::Chair => {
243
                writer.write_all(b"CHAIR")?;
244
            }
245
            Role::RequiredParticipant => {
246
                writer.write_all(b"REQ-PARTICIPANT")?;
247
            }
248
            Role::OptionalParticipant => {
249
                writer.write_all(b"OPT-PARTICIPANT")?;
250
            }
251
            Role::NonParticipant => {
252
6
                writer.write_all(b"NON-PARTICIPANT")?;
253
            }
254
            Role::XName(name) => {
255
                writer.write_all(name.as_bytes())?;
256
            }
257
            Role::IanaToken(token) => {
258
                writer.write_all(token.as_bytes())?;
259
            }
260
        }
261

            
262
6
        Ok(())
263
6
    }
264
}
265

            
266
impl WriteModel for crate::common::ParticipationStatusUnknown {
267
6
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
268
6
        use crate::common::ParticipationStatusUnknown;
269
6

            
270
6
        match self {
271
            ParticipationStatusUnknown::NeedsAction => {
272
4
                writer.write_all(b"NEEDS-ACTION")?;
273
            }
274
            ParticipationStatusUnknown::Accepted => {
275
2
                writer.write_all(b"ACCEPTED")?;
276
            }
277
            ParticipationStatusUnknown::Declined => {
278
                writer.write_all(b"DECLINED")?;
279
            }
280
            ParticipationStatusUnknown::Tentative => {
281
                writer.write_all(b"TENTATIVE")?;
282
            }
283
            ParticipationStatusUnknown::Delegated => {
284
                writer.write_all(b"DELEGATED")?;
285
            }
286
            ParticipationStatusUnknown::Completed => {
287
                writer.write_all(b"COMPLETED")?;
288
            }
289
            ParticipationStatusUnknown::InProcess => {
290
                writer.write_all(b"IN-PROCESS")?;
291
            }
292
            ParticipationStatusUnknown::XName(name) => {
293
                writer.write_all(name.as_bytes())?;
294
            }
295
            ParticipationStatusUnknown::IanaToken(token) => {
296
                writer.write_all(token.as_bytes())?;
297
            }
298
        }
299

            
300
6
        Ok(())
301
6
    }
302
}
303

            
304
impl WriteModel for bool {
305
6
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
306
6
        if *self {
307
6
            writer.write_all(b"TRUE")?;
308
        } else {
309
            writer.write_all(b"FALSE")?;
310
        }
311

            
312
6
        Ok(())
313
6
    }
314
}
315

            
316
impl WriteModel for crate::common::RelationshipType {
317
6
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
318
6
        use crate::common::RelationshipType;
319
6

            
320
6
        match self {
321
            RelationshipType::Parent => {
322
6
                writer.write_all(b"PARENT")?;
323
            }
324
            RelationshipType::Child => {
325
                writer.write_all(b"CHILD")?;
326
            }
327
            RelationshipType::Sibling => {
328
                writer.write_all(b"SIBLING")?;
329
            }
330
            RelationshipType::XName(name) => {
331
                writer.write_all(name.as_bytes())?;
332
            }
333
            RelationshipType::IanaToken(token) => {
334
                writer.write_all(token.as_bytes())?;
335
            }
336
        }
337

            
338
6
        Ok(())
339
6
    }
340
}
341

            
342
impl WriteModel for crate::common::FreeBusyTimeType {
343
2
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
344
2
        use crate::common::FreeBusyTimeType;
345
2

            
346
2
        match self {
347
            FreeBusyTimeType::Free => {
348
                writer.write_all(b"FREE")?;
349
            }
350
            FreeBusyTimeType::Busy => {
351
                writer.write_all(b"BUSY")?;
352
            }
353
            FreeBusyTimeType::BusyUnavailable => {
354
                writer.write_all(b"BUSY-UNAVAILABLE")?;
355
            }
356
            FreeBusyTimeType::BusyTentative => {
357
2
                writer.write_all(b"BUSY-TENTATIVE")?;
358
            }
359
            FreeBusyTimeType::XName(name) => {
360
                writer.write_all(name.as_bytes())?;
361
            }
362
            FreeBusyTimeType::IanaToken(token) => {
363
                writer.write_all(token.as_bytes())?;
364
            }
365
        }
366

            
367
2
        Ok(())
368
2
    }
369
}
370

            
371
impl WriteModel for crate::common::TriggerRelationship {
372
4
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
373
4
        use crate::common::TriggerRelationship;
374
4

            
375
4
        match self {
376
            TriggerRelationship::Start => {
377
2
                writer.write_all(b"START")?;
378
            }
379
            TriggerRelationship::End => {
380
2
                writer.write_all(b"END")?;
381
            }
382
        }
383

            
384
4
        Ok(())
385
4
    }
386
}
387

            
388
impl WriteModel for crate::model::property::Classification {
389
16
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
390
16
        use crate::model::property::Classification;
391
16

            
392
16
        match self {
393
            Classification::Public => {
394
10
                writer.write_all(b"PUBLIC")?;
395
            }
396
            Classification::Private => {
397
2
                writer.write_all(b"PRIVATE")?;
398
            }
399
            Classification::Confidential => {
400
4
                writer.write_all(b"CONFIDENTIAL")?;
401
            }
402
            Classification::XName(name) => {
403
                writer.write_all(name.as_bytes())?;
404
            }
405
            Classification::IanaToken(token) => {
406
                writer.write_all(token.as_bytes())?;
407
            }
408
        }
409

            
410
16
        Ok(())
411
16
    }
412
}
413

            
414
impl WriteModel for crate::common::TimeTransparency {
415
8
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
416
8
        use crate::common::TimeTransparency;
417
8

            
418
8
        match self {
419
            TimeTransparency::Opaque => {
420
2
                writer.write_all(b"OPAQUE")?;
421
            }
422
            TimeTransparency::Transparent => {
423
6
                writer.write_all(b"TRANSPARENT")?;
424
            }
425
        }
426

            
427
8
        Ok(())
428
8
    }
429
}
430

            
431
impl WriteModel for crate::model::property::RecurrenceRule {
432
38
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
433
        use crate::model::property::RecurRulePart;
434

            
435
270
        for part in &self.parts {
436
232
            match part {
437
38
                RecurRulePart::Freq(freq) => {
438
38
                    writer.write_all(b"FREQ=")?;
439
38
                    freq.write_model(writer)?;
440
                }
441
22
                RecurRulePart::Until(until) => {
442
22
                    writer.write_all(b";UNTIL=")?;
443
22
                    until.write_model(writer)?;
444
                }
445
10
                RecurRulePart::Count(count) => {
446
10
                    write!(writer, ";COUNT={}", count)?;
447
                }
448
10
                RecurRulePart::Interval(interval) => {
449
10
                    write!(writer, ";INTERVAL={}", interval)?;
450
                }
451
10
                RecurRulePart::BySecList(by_second) => {
452
10
                    write!(writer, ";BYSECOND=")?;
453
10
                    by_second.write_model(writer)?;
454
                }
455
10
                RecurRulePart::ByMinute(by_minute) => {
456
10
                    write!(writer, ";BYMINUTE=")?;
457
10
                    by_minute.write_model(writer)?;
458
                }
459
10
                RecurRulePart::ByHour(by_hour) => {
460
10
                    write!(writer, ";BYHOUR=")?;
461
10
                    by_hour.write_model(writer)?;
462
                }
463
36
                RecurRulePart::ByDay(by_day) => {
464
36
                    write!(writer, ";BYDAY=")?;
465
36
                    if let Some(day) = by_day.first() {
466
36
                        day.write_model(writer)?;
467
                    }
468
36
                    for day in by_day.iter().skip(1) {
469
                        write!(writer, ",")?;
470
                        day.write_model(writer)?;
471
                    }
472
                }
473
10
                RecurRulePart::ByMonthDay(by_month_day) => {
474
10
                    write!(writer, ";BYMONTHDAY=")?;
475
10
                    by_month_day.write_model(writer)?;
476
                }
477
10
                RecurRulePart::ByYearDay(by_year_day) => {
478
10
                    write!(writer, ";BYYEARDAY=")?;
479
10
                    by_year_day.write_model(writer)?;
480
                }
481
10
                RecurRulePart::ByWeekNumber(by_week_number) => {
482
10
                    write!(writer, ";BYWEEKNO=")?;
483
10
                    by_week_number.write_model(writer)?;
484
                }
485
36
                RecurRulePart::ByMonth(by_month) => {
486
36
                    write!(writer, ";BYMONTH=")?;
487
36
                    if let Some(month) = by_month.first() {
488
36
                        month.write_model(writer)?;
489
                    }
490
46
                    for month in by_month.iter().skip(1) {
491
20
                        write!(writer, ",")?;
492
20
                        month.write_model(writer)?;
493
                    }
494
                }
495
10
                RecurRulePart::BySetPos(by_set_pos) => {
496
10
                    write!(writer, ";BYSETPOS=")?;
497
10
                    by_set_pos.write_model(writer)?;
498
                }
499
10
                RecurRulePart::WeekStart(week_start) => {
500
10
                    write!(writer, ";WKST=")?;
501
10
                    week_start.write_model(writer)?;
502
                }
503
            }
504
        }
505

            
506
38
        Ok(())
507
38
    }
508
}
509

            
510
impl WriteModel for crate::common::RecurFreq {
511
38
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
512
38
        use crate::common::RecurFreq;
513
38

            
514
38
        match self {
515
            RecurFreq::Secondly => {
516
                writer.write_all(b"SECONDLY")?;
517
            }
518
            RecurFreq::Minutely => {
519
                writer.write_all(b"MINUTELY")?;
520
            }
521
            RecurFreq::Hourly => {
522
                writer.write_all(b"HOURLY")?;
523
            }
524
            RecurFreq::Daily => {
525
                writer.write_all(b"DAILY")?;
526
            }
527
            RecurFreq::Weekly => {
528
                writer.write_all(b"WEEKLY")?;
529
            }
530
            RecurFreq::Monthly => {
531
                writer.write_all(b"MONTHLY")?;
532
            }
533
            RecurFreq::Yearly => {
534
38
                writer.write_all(b"YEARLY")?;
535
            }
536
        }
537

            
538
38
        Ok(())
539
38
    }
540
}
541

            
542
impl<T: Add<Output = T> + std::fmt::Display> WriteModel for Vec<T> {
543
70
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
544
70
        if let Some(value) = self.first() {
545
70
            write!(writer, "{}", value)?;
546
        }
547
140
        for value in self.iter().skip(1) {
548
140
            write!(writer, ",{}", value)?;
549
        }
550

            
551
70
        Ok(())
552
70
    }
553
}
554

            
555
impl WriteModel for crate::common::OffsetWeekday {
556
36
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
557
36
        if let Some(offset_weeks) = &self.offset_weeks {
558
26
            write!(writer, "{}", offset_weeks)?;
559
10
        }
560

            
561
36
        self.weekday.write_model(writer)?;
562

            
563
36
        Ok(())
564
36
    }
565
}
566

            
567
impl WriteModel for crate::common::Weekday {
568
46
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
569
46
        use crate::common::Weekday;
570
46

            
571
46
        match self {
572
            Weekday::Sunday => {
573
26
                writer.write_all(b"SU")?;
574
            }
575
            Weekday::Monday => {
576
20
                writer.write_all(b"MO")?;
577
            }
578
            Weekday::Tuesday => {
579
                writer.write_all(b"TU")?;
580
            }
581
            Weekday::Wednesday => {
582
                writer.write_all(b"WE")?;
583
            }
584
            Weekday::Thursday => {
585
                writer.write_all(b"TH")?;
586
            }
587
            Weekday::Friday => {
588
                writer.write_all(b"FR")?;
589
            }
590
            Weekday::Saturday => {
591
                writer.write_all(b"SA")?;
592
            }
593
        }
594

            
595
46
        Ok(())
596
46
    }
597
}
598

            
599
impl WriteModel for time::Month {
600
56
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
601
56
        write!(writer, "{}", (*self) as u8)?;
602

            
603
56
        Ok(())
604
56
    }
605
}
606

            
607
impl WriteModel for crate::model::property::Duration {
608
32
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
609
32
        let write_time: fn(&mut W, &crate::model::property::Duration) -> anyhow::Result<()> =
610
30
            |writer, duration| {
611
30
                if duration.hours.is_some()
612
14
                    || duration.minutes.is_some()
613
8
                    || duration.seconds.is_some()
614
                {
615
22
                    writer.write_all(b"T")?;
616
                } else {
617
8
                    return Ok(());
618
                }
619

            
620
22
                if let Some(hours) = duration.hours {
621
16
                    write!(writer, "{}H", hours)?;
622

            
623
16
                    if let Some(minutes) = duration.minutes {
624
6
                        write!(writer, "{}M", minutes)?;
625

            
626
6
                        if let Some(seconds) = duration.seconds {
627
                            write!(writer, "{}S", seconds)?;
628
6
                        }
629
10
                    }
630
6
                } else if let Some(minutes) = duration.minutes {
631
6
                    write!(writer, "{}M", minutes)?;
632

            
633
6
                    if let Some(seconds) = duration.seconds {
634
                        write!(writer, "{}S", seconds)?;
635
6
                    }
636
                } else if let Some(seconds) = duration.seconds {
637
                    write!(writer, "{}S", seconds)?;
638
                }
639

            
640
22
                Ok(())
641
30
            };
642

            
643
32
        if self.sign < 0 {
644
4
            writer.write_all(b"-")?;
645
28
        }
646

            
647
32
        writer.write_all(b"P")?;
648

            
649
32
        if let Some(weeks) = &self.weeks {
650
2
            write!(writer, "{}W", weeks)?;
651
30
        } else if let Some(days) = &self.days {
652
8
            write!(writer, "{}D", days)?;
653
8
            write_time(writer, self)?;
654
        } else {
655
22
            write_time(writer, self)?;
656
        }
657

            
658
32
        Ok(())
659
32
    }
660
}
661

            
662
impl WriteModel for crate::common::Status {
663
10
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
664
10
        use crate::common::Status;
665
10

            
666
10
        match self {
667
            Status::Tentative => {
668
                writer.write_all(b"TENTATIVE")?;
669
            }
670
            Status::Confirmed => {
671
2
                writer.write_all(b"CONFIRMED")?;
672
            }
673
            Status::Cancelled => {
674
                writer.write_all(b"CANCELLED")?;
675
            }
676
            Status::NeedsAction => {
677
4
                writer.write_all(b"NEEDS-ACTION")?;
678
            }
679
            Status::Completed => {
680
                writer.write_all(b"COMPLETED")?;
681
            }
682
            Status::InProcess => {
683
2
                writer.write_all(b"IN-PROCESS")?;
684
            }
685
            Status::Draft => {
686
2
                writer.write_all(b"DRAFT")?;
687
            }
688
            Status::Final => {
689
                writer.write_all(b"FINAL")?;
690
            }
691
        }
692

            
693
10
        Ok(())
694
10
    }
695
}
696

            
697
impl WriteModel for crate::model::property::Period {
698
16
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
699
16
        self.start.write_model(writer)?;
700
16
        writer.write_all(b"/")?;
701
16
        match &self.end {
702
8
            crate::model::property::PeriodEnd::Duration(duration) => {
703
8
                duration.write_model(writer)?;
704
            }
705
8
            crate::model::property::PeriodEnd::DateTime(date_time) => {
706
8
                date_time.write_model(writer)?;
707
            }
708
        }
709

            
710
16
        Ok(())
711
16
    }
712
}
713

            
714
impl WriteModel for crate::model::property::TimeZoneOffset {
715
72
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
716
72
        if self.sign < 0 {
717
68
            writer.write_all(b"-")?;
718
        } else {
719
4
            writer.write_all(b"+")?;
720
        }
721

            
722
72
        write!(writer, "{:02}{:02}", self.hours, self.minutes)?;
723

            
724
72
        if let Some(seconds) = self.seconds {
725
            write!(writer, "{:02}", seconds)?;
726
72
        }
727

            
728
72
        Ok(())
729
72
    }
730
}
731

            
732
impl WriteModel for crate::model::property::Action {
733
14
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
734
14
        use crate::model::property::Action;
735
14

            
736
14
        match self {
737
            Action::Audio => {
738
4
                writer.write_all(b"AUDIO")?;
739
            }
740
            Action::Display => {
741
6
                writer.write_all(b"DISPLAY")?;
742
            }
743
            Action::Email => {
744
4
                writer.write_all(b"EMAIL")?;
745
            }
746
            Action::XName(name) => {
747
                writer.write_all(name.as_bytes())?;
748
            }
749
            Action::IanaToken(token) => {
750
                writer.write_all(token.as_bytes())?;
751
            }
752
        }
753

            
754
14
        Ok(())
755
14
    }
756
}
757

            
758
impl WriteModel for String {
759
188
    fn write_model<W: Write>(&self, writer: &mut W) -> anyhow::Result<()> {
760
188
        let mut out = Vec::with_capacity(self.len());
761
3642
        for c in self.chars() {
762
3642
            if matches!(c as u8, b';' | b'\\' | b',') {
763
4
                out.extend_from_slice(&[b'\\', c as u8]);
764
3638
            } else if c == '\n' {
765
6
                out.extend_from_slice(&[b'\\', b'n']);
766
3632
            } else {
767
3632
                out.push(c as u8);
768
3632
            }
769
        }
770

            
771
188
        writer.write_all(out.as_slice())?;
772

            
773
188
        Ok(())
774
188
    }
775
}