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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Contains the `TrafficModel` enum and its associated traits. It is used to
//! select a traffic model that is as accurate as possible, optimistic, or
//! pessimistic.

use crate::directions::error::Error as DirectionsError;
use crate::error::Error as GoogleMapsError;
use phf::phf_map;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

// -----------------------------------------------------------------------------

/// Specifies the [traffic
/// model](https://developers.google.com/maps/documentation/directions/intro#optional-parameters)
/// to use when calculating time in traffic.
///
/// This setting affects the value returned in the `duration_in_traffic` field
/// in the response, which contains the predicted time in traffic based on
/// historical averages. The `traffic_model` parameter may only be specified for
/// driving directions where the request includes a `departure_time`, and only
/// if the request includes an API key or a Google Maps Platform Premium Plan
/// client ID.
///
/// The default value of `best_guess` will give the most useful predictions for
/// the vast majority of use cases. It is possible the `best_guess` travel time
/// prediction may be _shorter_ than `optimistic`, or alternatively, _longer_
/// than `pessimistic`, due to the way the `best_guess` prediction model
/// integrates live traffic information.

#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum TrafficModel {
    /// Indicates that the returned `duration_in_traffic` should be the best
    /// estimate of travel time given what is known about both historical
    /// traffic conditions and live traffic. Live traffic becomes more important
    /// the closer the `departure_time` is to now.
    #[default] BestGuess = 0,
    /// Indicates that the returned duration_in_traffic should be shorter than
    /// the actual travel time on most days, though occasional days with
    /// particularly good traffic conditions may be faster than this value.
    Optimistic = 1,
    /// Indicates that the returned `duration_in_traffic` should be longer than
    /// the actual travel time on most days, though occasional days with
    /// particularly bad traffic conditions may exceed this value.
    Pessimistic = 2,
} // enum

// -----------------------------------------------------------------------------

impl<'de> Deserialize<'de> for TrafficModel {
    /// Manual implementation of `Deserialize` for `serde`. This will take
    /// advantage of the `phf`-powered `TryFrom` implementation for this type.
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let string = String::deserialize(deserializer)?;
        match TrafficModel::try_from(string.as_str()) {
            Ok(variant) => Ok(variant),
            Err(error) => Err(serde::de::Error::custom(error.to_string()))
        } // match
    } // fn
} // impl

// -----------------------------------------------------------------------------

impl Serialize for TrafficModel {
    /// Manual implementation of `Serialize` for `serde`.
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer {
        serializer.serialize_str(std::convert::Into::<&str>::into(self))
    } // fn
} // impl

// -----------------------------------------------------------------------------

impl std::convert::From<&TrafficModel> for &str {
    /// Converts a `TrafficModel` enum to a `String` that contains a [traffic
    /// model](https://developers.google.com/maps/documentation/javascript/reference/directions#TrafficModel)
    /// code.
    fn from(traffic_model: &TrafficModel) -> Self {
        match traffic_model {
            TrafficModel::BestGuess => "best_guess",
            TrafficModel::Optimistic => "optimistic",
            TrafficModel::Pessimistic => "pessimistic",
        } // match
    } // fn
} // impl

// -----------------------------------------------------------------------------

impl std::fmt::Display for TrafficModel {
    /// Converts a `TrafficModel` enum to a `String` that contains a [traffic
    /// model](https://developers.google.com/maps/documentation/javascript/reference/directions#TrafficModel)
    /// code.
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", std::convert::Into::<&str>::into(self))
    } // fmt
} // impl

// -----------------------------------------------------------------------------

impl std::convert::From<&TrafficModel> for String {
    /// Converts a `TrafficModel` enum to a `String` that contains a [traffic
    /// model](https://developers.google.com/maps/documentation/javascript/reference/directions#TrafficModel)
    /// code.
    fn from(traffic_model: &TrafficModel) -> Self {
        std::convert::Into::<&str>::into(traffic_model).to_string()
    } // fn
} // impl

// -----------------------------------------------------------------------------

static TRAFFIC_MODELS_BY_CODE: phf::Map<&'static str, TrafficModel> = phf_map! {
    "best_guess" => TrafficModel::BestGuess,
    "optimistic" => TrafficModel::Optimistic,
    "pessimistic" => TrafficModel::Pessimistic,
};

// -----------------------------------------------------------------------------

impl std::convert::TryFrom<&str> for TrafficModel {
    // Error definitions are contained in the
    // `google_maps\src\directions\error.rs` module.
    type Error = GoogleMapsError;
    /// Gets a `TrafficModel` enum from a `String` that contains a valid
    /// [traffic
    /// model](https://developers.google.com/maps/documentation/javascript/reference/directions#TrafficModel)
    /// code.
    fn try_from(traffic_model_code: &str) -> Result<Self, Self::Error> {
        Ok(TRAFFIC_MODELS_BY_CODE
            .get(traffic_model_code)
            .cloned()
            .ok_or_else(|| DirectionsError::InvalidTrafficModelCode(traffic_model_code.to_string()))?)
    } // fn
} // impl

// -----------------------------------------------------------------------------

impl std::str::FromStr for TrafficModel {
    // Error definitions are contained in the
    // `google_maps\src\directions\error.rs` module.
    type Err = GoogleMapsError;
    /// Gets a `TrafficModel` enum from a `String` that contains a valid
    /// [traffic
    /// model](https://developers.google.com/maps/documentation/javascript/reference/directions#TrafficModel)
    /// code.
    fn from_str(traffic_model_code: &str) -> Result<Self, Self::Err> {
        Ok(TRAFFIC_MODELS_BY_CODE
            .get(traffic_model_code)
            .cloned()
            .ok_or_else(|| DirectionsError::InvalidTrafficModelCode(traffic_model_code.to_string()))?)
    } // fn
} // impl

// -----------------------------------------------------------------------------

impl TrafficModel {
    /// Formats a `TrafficModel` enum into a string that is presentable to the
    /// end user.
    pub fn display(&self) -> &str {
        match self {
            TrafficModel::BestGuess => "Best Guess",
            TrafficModel::Optimistic => "Optimistic",
            TrafficModel::Pessimistic => "Pessimistic",
        } // match
    } // fn
} // impl