1use chrono::{Date, FixedOffset};
4use serde::{Deserialize, Serialize};
5
6use super::*;
7
8pub type Services = Vec<Service>;
10
11pub type Service = Resource<ServiceAttributes>;
13
14#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
16pub struct ServiceAttributes {
17 pub valid_days: Vec<Day>,
19 #[serde(with = "mbta_date_format")]
21 pub start_date: Date<FixedOffset>,
22 pub schedule_typicality: ScheduleTypicality,
24 pub schedule_type: Option<String>,
26 pub schedule_name: Option<String>,
28 pub removed_dates_notes: Vec<Option<String>>,
30 #[serde(with = "vec_mbta_date_format")]
32 pub removed_dates: Vec<Date<FixedOffset>>,
33 #[serde(with = "optional_mbta_date_format")]
35 pub rating_start_date: Option<Date<FixedOffset>>,
36 #[serde(with = "optional_mbta_date_format")]
38 pub rating_end_date: Option<Date<FixedOffset>>,
39 pub rating_description: Option<String>,
41 #[serde(with = "mbta_date_format")]
43 pub end_date: Date<FixedOffset>,
44 pub description: Option<String>,
46 pub added_dates_notes: Vec<Option<String>>,
48 #[serde(with = "vec_mbta_date_format")]
50 pub added_dates: Vec<Date<FixedOffset>>,
51}
52
53#[derive(Debug, PartialEq, Clone, Copy, Deserialize, Serialize)]
55#[serde(try_from = "u8")]
56#[serde(into = "u8")]
57pub enum ScheduleTypicality {
58 Undefined,
60 Typical,
62 Extra,
64 Reduced,
66 Disrupted,
68 Atypical,
70}
71
72impl TryFrom<u8> for ScheduleTypicality {
73 type Error = String;
74
75 fn try_from(value: u8) -> Result<Self, Self::Error> {
76 match value {
77 0 => Ok(Self::Undefined),
78 1 => Ok(Self::Typical),
79 2 => Ok(Self::Extra),
80 3 => Ok(Self::Reduced),
81 4 => Ok(Self::Disrupted),
82 5 => Ok(Self::Atypical),
83 _ => Err(format!("invalid schedule typicality value: {}", value)),
84 }
85 }
86}
87
88impl From<ScheduleTypicality> for u8 {
89 fn from(value: ScheduleTypicality) -> Self {
90 match value {
91 ScheduleTypicality::Undefined => 0,
92 ScheduleTypicality::Typical => 1,
93 ScheduleTypicality::Extra => 2,
94 ScheduleTypicality::Reduced => 3,
95 ScheduleTypicality::Disrupted => 4,
96 ScheduleTypicality::Atypical => 5,
97 }
98 }
99}
100
101#[derive(Debug, PartialEq, Clone, Copy, Deserialize, Serialize)]
103#[serde(try_from = "u8")]
104#[serde(into = "u8")]
105pub enum Day {
106 Monday,
108 Tuesday,
110 Wednesday,
112 Thursday,
114 Friday,
116 Saturday,
118 Sunday,
120}
121
122impl TryFrom<u8> for Day {
123 type Error = String;
124
125 fn try_from(value: u8) -> Result<Self, Self::Error> {
126 match value {
127 1 => Ok(Self::Monday),
128 2 => Ok(Self::Tuesday),
129 3 => Ok(Self::Wednesday),
130 4 => Ok(Self::Thursday),
131 5 => Ok(Self::Friday),
132 6 => Ok(Self::Saturday),
133 7 => Ok(Self::Sunday),
134 _ => Err(format!("invalid day value: {}", value)),
135 }
136 }
137}
138
139impl From<Day> for u8 {
140 fn from(value: Day) -> Self {
141 match value {
142 Day::Monday => 1,
143 Day::Tuesday => 2,
144 Day::Wednesday => 3,
145 Day::Thursday => 4,
146 Day::Friday => 5,
147 Day::Saturday => 6,
148 Day::Sunday => 7,
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 use rstest::*;
158
159 #[rstest]
160 #[case::zero(0, Ok(ScheduleTypicality::Undefined))]
161 #[case::one(1, Ok(ScheduleTypicality::Typical))]
162 #[case::two(2, Ok(ScheduleTypicality::Extra))]
163 #[case::three(3, Ok(ScheduleTypicality::Reduced))]
164 #[case::four(4, Ok(ScheduleTypicality::Disrupted))]
165 #[case::five(5, Ok(ScheduleTypicality::Atypical))]
166 #[case::invalid(6, Err("invalid schedule typicality value: 6".into()))]
167 fn test_schedule_typicality_try_from_u8(#[case] input: u8, #[case] expected: Result<ScheduleTypicality, String>) {
168 assert_eq!(ScheduleTypicality::try_from(input), expected);
169 }
170
171 #[rstest]
172 #[case::undefined(ScheduleTypicality::Undefined, 0)]
173 #[case::typical(ScheduleTypicality::Typical, 1)]
174 #[case::extra(ScheduleTypicality::Extra, 2)]
175 #[case::reduced(ScheduleTypicality::Reduced, 3)]
176 #[case::disrupted(ScheduleTypicality::Disrupted, 4)]
177 #[case::atypical(ScheduleTypicality::Atypical, 5)]
178 fn test_u8_from_schedule_typicality(#[case] input: ScheduleTypicality, #[case] expected: u8) {
179 assert_eq!(u8::from(input), expected);
180 }
181
182 #[rstest]
183 #[case::one(1, Ok(Day::Monday))]
184 #[case::two(2, Ok(Day::Tuesday))]
185 #[case::three(3, Ok(Day::Wednesday))]
186 #[case::four(4, Ok(Day::Thursday))]
187 #[case::five(5, Ok(Day::Friday))]
188 #[case::six(6, Ok(Day::Saturday))]
189 #[case::seven(7, Ok(Day::Sunday))]
190 #[case::invalid(8, Err("invalid day value: 8".into()))]
191 fn test_day_try_from_u8(#[case] input: u8, #[case] expected: Result<Day, String>) {
192 assert_eq!(Day::try_from(input), expected);
193 }
194
195 #[rstest]
196 #[case::monday(Day::Monday, 1)]
197 #[case::tuesday(Day::Tuesday, 2)]
198 #[case::wednesday(Day::Wednesday, 3)]
199 #[case::thursday(Day::Thursday, 4)]
200 #[case::friday(Day::Friday, 5)]
201 #[case::saturday(Day::Saturday, 6)]
202 #[case::sunday(Day::Sunday, 7)]
203 fn test_u8_from_day(#[case] input: Day, #[case] expected: u8) {
204 assert_eq!(u8::from(input), expected);
205 }
206}