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
//! Roads API error types and error messages.

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

use crate::roads::status::Status;
use miette::Diagnostic;
use thiserror::Error;

// -----------------------------------------------------------------------------
//
/// Errors that may be produced by the Google Maps Roads API client.

#[derive(Debug, Diagnostic, Error)]
#[diagnostic(code(google_maps::roads::error), url(docsrs))]
pub enum Error {
    /// Google Maps Roads API server generated an error. See the `Status`
    /// enum for more information.
    GoogleMapsService(Status, Option<String>),

    /// The HTTP request was unsuccessful.
    HttpUnsuccessful(String),

    /// API client library attempted to parse a string that contained an invalid
    /// status code. See `google_maps\src\time_zone\response\status.rs` for more
    /// information.
    InvalidStatusCode(String),

    /// The query string must be built before the request may be sent to the
    /// Google Maps Roads API server.
    QueryNotBuilt,

    /// The dependency library Reqwest generated an error.
    #[cfg(feature = "enable-reqwest")]
    Reqwest(crate::ReqError),

    /// The dependency library Reqwest generated an error. The error could
    /// not be passed normally so a `String` representation is passed instead.
    #[cfg(feature = "enable-reqwest")]
    ReqwestMessage(String),

    /// The dependency library Serde JSON generated an error.
    SerdeJson(serde_json::error::Error),
} // enum

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

impl std::fmt::Display for Error {
    /// This trait converts the error code into a format that may be presented
    /// to the user.
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Self::GoogleMapsService(status, error_message) => match error_message {
                // If the Google Maps Roads API server generated an error
                // message, return that:
                Some(error_message) => write!(f, "Google Maps Roads API service: {error_message}"),
                // If the Google Maps Roads API server did not generate an
                // error message, return a generic message derived from the
                // response status:
                None => match status {
                    Status::InvalidArgument => write!(f, "Google Maps Roads API service: \
                        Invalid argument. \
                        1. Your API key is not valid or was not included in the request. \
                        or, 2. Your request contained invalid arguments."),
                    Status::PermissionDenied => write!(f, "Google Maps Roads API service: \
                        Permission Denied. \
                        1. API key missing or invalid. \
                        2. Billing not enabled. \
                        3. Self-imposed usage cap exceeded. \
                        or, 4. Method of payment no longer valid."),
                    Status::NotFound => write!(f, "Google Maps Roads API service: \
                        Not found. \
                        Ensure that you are sending requests \
                        to `https://roads.googleapis.com/` and not \
                        `http://roads.googleapis.com/`."),
                    Status::ResourceExhausted => write!(f, "Google Maps Roads API service: \
                        Not found. \
                        You have exceeded the request limit that you configured \
                        in the Google Cloud Platform Console."),
                } // match
            }, // match
            Self::HttpUnsuccessful(status) => write!(f,
                "Google Maps Roads API client: \
                Could not successfully query the Google Cloud Platform service. \
                The service last responded with a `{status}` status."),
            Self::InvalidStatusCode(status_code) => write!(f, "Google Maps Roads API client: \
                `{status_code}` is not a valid status code. \
                Valid codes are `INVALID_ARGUMENT`, `PERMISSION_DENIED`, \
                `NOT_FOUND`, and `RESOURCE_EXHAUSTED`."),
            Self::QueryNotBuilt => write!(f, "Google Maps Roads API client library: \
                The query string must be built before the request may be sent to the Google Cloud Maps Platform. \
                Ensure the build() method is called before run()."),
            #[cfg(feature = "enable-reqwest")]
            Self::Reqwest(error) => write!(f, "Google Maps Roads API client in the Reqwest library: {error}"),
            #[cfg(feature = "enable-reqwest")]
            Self::ReqwestMessage(error) => write!(f, "Google Maps Geocoding API client in the Reqwest library: {error}"),
            Self::SerdeJson(error) => write!(f, "Google Maps Roads API client in the Serde JSON library: {error}"),
        } // match
    } // fn
} // impl

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

#[cfg(feature = "enable-reqwest")]
impl From<reqwest::Error> for Error {
    /// This trait converts from an Reqwest error type (`reqwest::Error`) into a
    /// Google Maps Roads API error type
    /// (`google_maps::time_zone::error::Error`) by wrapping it inside. This
    /// function is required to use the `?` operator.
    fn from(error: reqwest::Error) -> Self {
        Self::Reqwest(crate::ReqError::from(error))
    } // fn
} // impl

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

impl From<serde_json::error::Error> for Error {
    /// This trait converts from an Serde JSON (`serde_json::error::Error`)
    /// error type into a Google Maps Roads API error type
    /// (`google_maps::time_zone::error::Error`) by wrapping it inside. This
    /// function is required to use the `?` operator.
    fn from(error: serde_json::error::Error) -> Self {
        Self::SerdeJson(error)
    } // fn
} // impl