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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
774
188
        Ok(())
775
188
    }
776
}