1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use core::fmt::Debug;

use super::{
    error::Error,
    helper::{encode_closing_tag, encode_opening_tag, get_tagged_body},
    io::{Reader, Writer},
    time_value::TimeValue,
};

// note that Debug is implemented manually here because of the reader in time value iter
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct WeeklySchedule<'a> {
    pub monday: TimeValueList<'a>,
    pub tuesday: TimeValueList<'a>,
    pub wednesday: TimeValueList<'a>,
    pub thursday: TimeValueList<'a>,
    pub friday: TimeValueList<'a>,
    pub saturday: TimeValueList<'a>,
    pub sunday: TimeValueList<'a>,
}

impl<'a> WeeklySchedule<'a> {
    pub fn new(
        monday: &'a [TimeValue],
        tuesday: &'a [TimeValue],
        wednesday: &'a [TimeValue],
        thursday: &'a [TimeValue],
        friday: &'a [TimeValue],
        saturday: &'a [TimeValue],
        sunday: &'a [TimeValue],
    ) -> Self {
        Self {
            monday: TimeValueList::new(monday),
            tuesday: TimeValueList::new(tuesday),
            wednesday: TimeValueList::new(wednesday),
            thursday: TimeValueList::new(thursday),
            friday: TimeValueList::new(friday),
            saturday: TimeValueList::new(saturday),
            sunday: TimeValueList::new(sunday),
        }
    }

    pub fn encode(&self, writer: &mut Writer) {
        self.monday.encode(writer);
        self.tuesday.encode(writer);
        self.wednesday.encode(writer);
        self.thursday.encode(writer);
        self.friday.encode(writer);
        self.saturday.encode(writer);
        self.sunday.encode(writer);
    }

    // due to the fact that WeeklySchedule contains an arbitrary number of TimeValue pairs we need to return an iterator
    // because we cannot use an allocator
    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
        let monday = TimeValueList::decode(reader, buf)?;
        let tuesday = TimeValueList::decode(reader, buf)?;
        let wednesday = TimeValueList::decode(reader, buf)?;
        let thursday = TimeValueList::decode(reader, buf)?;
        let friday = TimeValueList::decode(reader, buf)?;
        let saturday = TimeValueList::decode(reader, buf)?;
        let sunday = TimeValueList::decode(reader, buf)?;

        Ok(Self {
            monday,
            tuesday,
            wednesday,
            thursday,
            friday,
            saturday,
            sunday,
        })
    }
}

// note that Debug is not implemented here because if does not add value
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct TimeValueList<'a> {
    pub time_values: &'a [TimeValue],
    buf: &'a [u8],
}

impl<'a> TimeValueList<'a> {
    pub fn new(time_values: &'a [TimeValue]) -> Self {
        Self {
            time_values,
            buf: &[],
        }
    }

    pub fn new_from_buf(buf: &'a [u8]) -> Self {
        Self {
            time_values: &[],
            buf,
        }
    }

    pub fn encode(&self, writer: &mut Writer) {
        encode_opening_tag(writer, 0);
        for time_value in self.time_values {
            time_value.encode(writer)
        }
        encode_closing_tag(writer, 0);
    }

    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
        let (body_buf, _tag_num) = get_tagged_body(reader, buf)?;
        Ok(TimeValueList::new_from_buf(body_buf))
    }
}

impl<'a> IntoIterator for &'_ TimeValueList<'a> {
    type Item = Result<TimeValue, Error>;
    type IntoIter = TimeValueIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        TimeValueIter {
            buf: self.buf,
            reader: Reader::new_with_len(self.buf.len()),
        }
    }
}

pub struct TimeValueIter<'a> {
    reader: Reader,
    buf: &'a [u8],
}

impl<'a> Iterator for TimeValueIter<'a> {
    type Item = Result<TimeValue, Error>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.reader.eof() {
            return None;
        }

        Some(TimeValue::decode(&mut self.reader, self.buf))
    }
}