mbta_rs/models/
route_pattern.rs

1//! Data model for MBTA route patterns.
2
3use serde::{Deserialize, Serialize};
4
5use super::*;
6
7/// Multiple route patterns.
8pub type RoutePatterns = Vec<RoutePattern>;
9
10/// A different variation of service that may be run within a single route, including when and how often they are operated.
11pub type RoutePattern = Resource<RoutePatternAttributes>;
12
13/// Attributes for route pattern.
14#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
15pub struct RoutePatternAttributes {
16    /// The direction in which the trip is traveling: 0 or 1.
17    pub direction_id: u8,
18    /// User-facing description of where trips on the route pattern serve.
19    pub name: String,
20    /// Can be used to order the route patterns in a way which is ideal for presentation to customers.
21    /// Route patterns with smaller sort_order values should be displayed before those with larger values.
22    pub sort_order: u64,
23    /// User-facing description of when the route pattern operate.
24    pub time_desc: Option<String>,
25    /// Explains how common the route pattern is. For the MBTA, this is within the context of the entire route.
26    pub typicality: RoutePatternTypicality,
27}
28
29/// How common a route pattern is. For the MBTA, this is within the context of the entire route.
30#[derive(Deserialize, Serialize, Debug, PartialEq, Clone, Copy)]
31#[serde(try_from = "u8")]
32#[serde(into = "u8")]
33pub enum RoutePatternTypicality {
34    /// Not defined.
35    Undefined,
36    /// Typical. Pattern is common for the route. Most routes will have only one such pattern per direction.
37    /// A few routes may have more than 1, such as the Red Line (with one branch to Ashmont and another to Braintree);
38    /// routes with more than 2 are rare.
39    Typical,
40    /// Pattern is a deviation from the regular route.
41    Deviation,
42    /// Pattern represents a highly atypical pattern for the route, such as a special routing which only runs a handful of times per day.
43    HighlyAtypical,
44    /// Diversions from normal service, such as planned detours, bus shuttles, or snow routes.
45    NormalServiceDiversion,
46}
47
48impl TryFrom<u8> for RoutePatternTypicality {
49    type Error = String;
50
51    fn try_from(value: u8) -> Result<Self, Self::Error> {
52        match value {
53            0 => Ok(Self::Undefined),
54            1 => Ok(Self::Typical),
55            2 => Ok(Self::Deviation),
56            3 => Ok(Self::HighlyAtypical),
57            4 => Ok(Self::NormalServiceDiversion),
58            _ => Err(format!("invalid route pattern typicality: {}", value)),
59        }
60    }
61}
62
63impl From<RoutePatternTypicality> for u8 {
64    fn from(value: RoutePatternTypicality) -> Self {
65        match value {
66            RoutePatternTypicality::Undefined => 0,
67            RoutePatternTypicality::Typical => 1,
68            RoutePatternTypicality::Deviation => 2,
69            RoutePatternTypicality::HighlyAtypical => 3,
70            RoutePatternTypicality::NormalServiceDiversion => 4,
71        }
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    use rstest::*;
80
81    #[rstest]
82    #[case::zero(0, Ok(RoutePatternTypicality::Undefined))]
83    #[case::one(1, Ok(RoutePatternTypicality::Typical))]
84    #[case::two(2, Ok(RoutePatternTypicality::Deviation))]
85    #[case::three(3, Ok(RoutePatternTypicality::HighlyAtypical))]
86    #[case::four(4, Ok(RoutePatternTypicality::NormalServiceDiversion))]
87    #[case::invalid(5, Err("invalid route pattern typicality: 5".into()))]
88    fn test_route_pattern_typicality_try_from_u8(#[case] input: u8, #[case] expected: Result<RoutePatternTypicality, String>) {
89        assert_eq!(RoutePatternTypicality::try_from(input), expected);
90    }
91
92    #[rstest]
93    #[case::undefined(RoutePatternTypicality::Undefined, 0)]
94    #[case::typical(RoutePatternTypicality::Typical, 1)]
95    #[case::deviation(RoutePatternTypicality::Deviation, 2)]
96    #[case::higly_atypical(RoutePatternTypicality::HighlyAtypical, 3)]
97    #[case::normal_service_diversion(RoutePatternTypicality::NormalServiceDiversion, 4)]
98    fn test_u8_from_route_pattern_typicality(#[case] input: RoutePatternTypicality, #[case] expected: u8) {
99        assert_eq!(u8::from(input), expected);
100    }
101}