lta/
lib.rs

1#![doc = include_str!("../LIBDOC.md")]
2
3/// Helper macro to general API URL at compile time
4#[macro_export]
5macro_rules! api_url {
6    ($e: expr) => {
7        concat!("http://datamall2.mytransport.sg/ltaodataservice", $e)
8    };
9}
10
11pub use crate::r#async::prelude::*;
12pub use crate::r#async::LTAClient;
13pub use lta_models as models;
14use reqwest::StatusCode;
15use thiserror::Error;
16
17/// Imports for important structs
18pub mod prelude {
19    pub use crate::{Bus, Crowd, Facility, Geo, Taxi, Traffic, Train};
20}
21
22use crate::models::crowd::passenger_vol::VolType;
23pub use reqwest;
24
25/// Internal Async module
26pub mod r#async;
27
28/// Internal Blocking module
29#[cfg(feature = "blocking")]
30pub mod blocking;
31
32/// Type alias for `Result<T, LTAError>`
33pub type LTAResult<T> = Result<T, LTAError>;
34
35/// LTAError type, all request using lta-rs returns `Result<T, LTAError>`
36#[derive(Error, Debug)]
37pub enum LTAError {
38    /// Internal error within the client backend, open a PR if this happens
39    #[error("Internal error within the client backend, open a PR if this happens!")]
40    BackendError(#[from] reqwest::Error),
41    
42    /// API key is most likely empty
43    #[error("Invalid API Key!")]
44    InvalidAPIKey,
45
46    /// You have reached the server limit, try again later
47    #[error("Server rate limit reached!")]
48    RateLimitReached,
49
50    /// Response body can't be parsed to a valid enum
51    #[error("Unknown enum variant!")]
52    UnknownEnumVariant,
53
54    /// Make sure that your API key is correct and valid
55    #[error("HTTP Header Unauthorized")]
56    Unauthorized,
57
58    /// HTTP NOTFOUND
59    #[error("HTTP Header NotFound")]
60    NotFound,
61
62    /// Failed to parse body of response, probably malformed
63    #[error("Failed to parse body of response, probably malformed")]
64    FailedToParseBody,
65
66    /// Undocumented status code, open an issue if this happens
67    #[error("Undocumented status code, open an issue if this happens")]
68    UnhandledStatusCode(StatusCode, String),
69
70    /// Custom
71    #[error("Custom error: `{0}`")]
72    Custom(String),
73}
74
75/// A `Client` to make requests with
76/// The `Client` holds a connection pool internally, so it is advised that you create one and reuse it
77pub trait Client: Sized {
78    /// Any backend Client
79    type InternalClient;
80
81    /// Any type that can build requests
82    type RB;
83
84    /// General constructor for `Self`
85    fn new(api_key: impl Into<String>, client: Self::InternalClient) -> Self;
86
87    /// This method not assign the `api_key` in struct if the provided key is empty or whitespaces
88    /// Instead, assign `None`
89    fn with_api_key(api_key: impl Into<String>) -> LTAResult<Self>;
90
91    /// Returns `Self::RB`
92    fn req_builder(&self, url: &str) -> Self::RB;
93}
94
95/// Bus type that implements APIs. Can be either blocking or async
96#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
97pub struct Bus;
98
99/// Crowd type that implements APIs. Can be either blocking or async
100#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
101pub struct Crowd;
102
103/// Taxi type that implements APIs. Can be either blocking or async
104#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
105pub struct Taxi;
106
107/// Traffic type that implements APIs. Can be either blocking or async
108#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
109pub struct Traffic;
110
111/// Train type that implements APIs. Can be either blocking or async
112#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
113pub struct Train;
114
115/// Geo type that implements APIs. Can be either blocking or async
116#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
117pub struct Geo;
118
119/// Facility type that implements APIs. Can be either blocking or async
120#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
121pub struct Facility;
122
123/// util to map enum to url
124pub(crate) const fn vol_type_to_url(vol_type: VolType) -> LTAResult<&'static str> {
125    use crate::models::crowd::passenger_vol;
126
127    let url = match vol_type {
128        VolType::BusStops => passenger_vol::URL_BY_BUS_STOPS,
129        VolType::OdBusStop => passenger_vol::URL_BY_OD_BUS_STOPS,
130        VolType::Train => passenger_vol::URL_BY_TRAIN,
131        VolType::OdTrain => passenger_vol::URL_BY_OD_TRAIN,
132        _ => return Err(LTAError::UnknownEnumVariant),
133    };
134
135    Ok(url)
136}