1#![doc = include_str!("../README.md")]
2
3mod error;
4pub use error::*;
5
6use rcore::Requester;
7
8type R = rcore::ReqwestRequester;
10
11#[derive(Clone, rapi_derive::ProviderApi)]
20pub enum RailwayProvider {
21 #[cfg(feature = "vbb-provider")]
23 #[provider(hafas = rhafas::profile::vbb::VbbProfile {})]
24 Vbb(rhafas::client::HafasClient<R>),
25 #[cfg(feature = "oebb-provider")]
26 #[provider(hafas = rhafas::profile::oebb::OebbProfile {})]
27 Oebb(rhafas::client::HafasClient<R>),
28 #[cfg(feature = "nahsh-provider")]
29 #[provider(hafas = rhafas::profile::nahsh::NahSHProfile {})]
30 NahSh(rhafas::client::HafasClient<R>),
31 #[cfg(feature = "vvt-provider")]
32 #[provider(hafas = rhafas::profile::vvt::VvtProfile {})]
33 Vvt(rhafas::client::HafasClient<R>),
34 #[cfg(feature = "pkp-provider")]
35 #[provider(hafas = rhafas::profile::pkp::PkpProfile {})]
36 Pkp(rhafas::client::HafasClient<R>),
37 #[cfg(feature = "irish-rail-provider")]
38 #[provider(hafas = rhafas::profile::irish_rail::IrishRailProfile {})]
39 IrishRail(rhafas::client::HafasClient<R>),
40 #[cfg(feature = "mobiliteit-lu-provider")]
41 #[provider(hafas = rhafas::profile::mobiliteit_lu::MobiliteitLuProfile {})]
42 MobiliteitLu(rhafas::client::HafasClient<R>),
43 #[cfg(feature = "dart-provider")]
44 #[provider(hafas = rhafas::profile::dart::DartProfile {})]
45 Dart(rhafas::client::HafasClient<R>),
46 #[cfg(feature = "rmv-provider")]
47 #[provider(hafas = rhafas::profile::rmv::RmvProfile {})]
48 Rmv(rhafas::client::HafasClient<R>),
49 #[cfg(feature = "insa-provider")]
50 #[provider(hafas = rhafas::profile::insa::InsaProfile {})]
51 Insa(rhafas::client::HafasClient<R>),
52 #[cfg(feature = "cmta-provider")]
53 #[provider(hafas = rhafas::profile::cmta::CmtaProfile {})]
54 Cmta(rhafas::client::HafasClient<R>),
55 #[cfg(feature = "sbahn-muenchen-provider")]
56 #[provider(hafas = rhafas::profile::sbahn_muenchen::SBahnMuenchenProfile {})]
57 SBahnMuenchen(rhafas::client::HafasClient<R>),
58 #[cfg(feature = "saarvv-provider")]
59 #[provider(hafas = rhafas::profile::saarvv::SaarvvProfile {})]
60 Saarvv(rhafas::client::HafasClient<R>),
61 #[cfg(feature = "cfl-provider")]
62 #[provider(hafas = rhafas::profile::cfl::CflProfile {})]
63 Cfl(rhafas::client::HafasClient<R>),
64 #[cfg(feature = "nvv-provider")]
65 #[provider(hafas = rhafas::profile::nvv::NvvProfile {})]
66 Nvv(rhafas::client::HafasClient<R>),
67 #[cfg(feature = "mobil-nrw-provider")]
68 #[provider(hafas = rhafas::profile::mobil_nrw::MobilNrwProfile {})]
69 MobilNrw(rhafas::client::HafasClient<R>),
70 #[cfg(feature = "vsn-provider")]
71 #[provider(hafas = rhafas::profile::vsn::VsnProfile {})]
72 Vsn(rhafas::client::HafasClient<R>),
73 #[cfg(feature = "vgi-provider")]
74 #[provider(hafas = rhafas::profile::vgi::VgiProfile {})]
75 Vgi(rhafas::client::HafasClient<R>),
76 #[cfg(feature = "vbn-provider")]
77 #[provider(hafas = rhafas::profile::vbn::VbnProfile {})]
78 Vbn(rhafas::client::HafasClient<R>),
79 #[cfg(feature = "vrn-provider")]
80 #[provider(hafas = rhafas::profile::vrn::VrnProfile {})]
81 Vrn(rhafas::client::HafasClient<R>),
82 #[cfg(feature = "rsag-provider")]
83 #[provider(hafas = rhafas::profile::rsag::RsagProfile {})]
84 Rsag(rhafas::client::HafasClient<R>),
85 #[cfg(feature = "vmt-provider")]
86 #[provider(hafas = rhafas::profile::vmt::VmtProfile {})]
87 Vmt(rhafas::client::HafasClient<R>),
88 #[cfg(feature = "vos-provider")]
89 #[provider(hafas = rhafas::profile::vos::VosProfile {})]
90 Vos(rhafas::client::HafasClient<R>),
91 #[cfg(feature = "avv-provider")]
92 #[provider(hafas = rhafas::profile::avv::AvvProfile {})]
93 Avv(rhafas::client::HafasClient<R>),
94 #[cfg(feature = "rejseplanen-provider")]
95 #[provider(hafas = rhafas::profile::rejseplanen::RejseplanenProfile {})]
96 Rejseplanen(rhafas::client::HafasClient<R>),
97 #[cfg(feature = "ooevv-provider")]
98 #[provider(hafas = rhafas::profile::ooevv::OoevvProfile {})]
99 Ooevv(rhafas::client::HafasClient<R>),
100 #[cfg(feature = "salzburg-provider")]
101 #[provider(hafas = rhafas::profile::salzburg::SalzburgProfile {})]
102 Salzburg(rhafas::client::HafasClient<R>),
103 #[cfg(feature = "verbundlinie-provider")]
104 #[provider(hafas = rhafas::profile::verbundlinie::VerbundlinieProfile {})]
105 Verbundlinie(rhafas::client::HafasClient<R>),
106 #[cfg(feature = "svv-provider")]
107 #[provider(hafas = rhafas::profile::svv::SvvProfile {})]
108 Svv(rhafas::client::HafasClient<R>),
109 #[cfg(feature = "vor-provider")]
110 #[provider(hafas = rhafas::profile::vor::VorProfile {})]
111 Vor(rhafas::client::HafasClient<R>),
112 #[cfg(feature = "vkg-provider")]
113 #[provider(hafas = rhafas::profile::vkg::VkgProfile {})]
114 Vkg(rhafas::client::HafasClient<R>),
115 #[cfg(feature = "vvv-provider")]
116 #[provider(hafas = rhafas::profile::vvv::VvvProfile {})]
117 Vvv(rhafas::client::HafasClient<R>),
118 #[cfg(feature = "bls-provider")]
119 #[provider(hafas = rhafas::profile::bls::BlsProfile {})]
120 Bls(rhafas::client::HafasClient<R>),
121 #[cfg(feature = "kvb-provider")]
122 #[provider(hafas = rhafas::profile::kvb::KvbProfile {})]
123 Kvb(rhafas::client::HafasClient<R>),
124 #[cfg(feature = "bart-provider")]
125 #[provider(hafas = rhafas::profile::bart::BartProfile {})]
126 Bart(rhafas::client::HafasClient<R>),
127 #[cfg(feature = "ivb-provider")]
128 #[provider(hafas = rhafas::profile::ivb::IvbProfile {})]
129 Ivb(rhafas::client::HafasClient<R>),
130 #[cfg(feature = "resrobot-provider")]
131 #[provider(hafas = rhafas::profile::resrobot::ResrobotProfile {})]
132 Resrobot(rhafas::client::HafasClient<R>),
133
134 #[cfg(feature = "search-ch-provider")]
136 #[provider(constructor = rsearchch::SearchChClient::new)]
137 SearchCh(rsearchch::SearchChClient<R>),
138
139 #[cfg(feature = "transitous-provider")]
141 #[provider(constructor = |r| rmotis::MotisClient::new(url::Url::parse(rmotis::TRANSITOUS_URL).expect("Failed to parse TRANSITOUS_URL"), r))]
142 Transitous(rmotis::MotisClient),
143
144 #[cfg(feature = "db-provider")]
146 #[provider(constructor = rdb::DbMovasClient::new)]
147 Db(rdb::DbMovasClient<R>),
148}
149
150#[cfg(test)]
151mod api_test {
152 use super::*;
153
154 #[test]
155 #[cfg(feature = "db-provider")]
156 fn macro_creates_enum_types() {
157 let _ = RailwayProviderType::Db;
158 }
159
160 #[test]
161 #[cfg(feature = "db-provider")]
162 fn macro_creates_enum_type_variants() {
163 let list = RailwayProviderType::variants();
164 assert!(list.len() >= 1);
165 }
166
167 #[test]
168 #[cfg(feature = "db-provider")]
169 fn macro_creates_enum_from_to_string() {
170 use std::str::FromStr;
171 assert_eq!(
172 RailwayProviderType::from_str("db").unwrap(),
173 RailwayProviderType::Db
174 );
175 assert_eq!(RailwayProviderType::Db.to_string(), "db".to_owned());
176 }
177
178 #[test]
179 #[cfg(feature = "db-provider")]
180 fn macro_creates_constructor() {
181 let _ = RailwayProvider::new(
182 RailwayProviderType::Db,
183 rcore::ReqwestRequesterBuilder::default(),
184 );
185 }
186
187 #[test]
188 #[cfg(feature = "db-provider")]
189 fn macro_implements_provider() {
190 use rcore::Provider;
191
192 let client = RailwayProvider::new(
193 RailwayProviderType::Db,
194 rcore::ReqwestRequesterBuilder::default(),
195 );
196 let _ = Box::new(client) as Box<dyn Provider<rcore::ReqwestRequester, Error = BoxedError>>;
197 }
198
199 #[test]
200 #[cfg(feature = "all-providers")]
201 fn readme_supported_up_to_date() {
202 use std::collections::HashSet;
203
204 let supported: HashSet<_> = RailwayProviderType::variants()
205 .into_iter()
206 .map(|p| p.to_string().to_lowercase().replace(&['-', '_'], ""))
207 .collect();
208 let readme = include_str!("../../README.md").lines();
209
210 let entries: HashSet<_> = readme
211 .skip_while(|l| l != &"## Profiles")
213 .skip_while(|l| !l.starts_with("|"))
215 .skip(2)
217 .take_while(|l| l.starts_with("|"))
219 .flat_map(|r| r.split('|').nth(1))
221 .map(|s| s.trim().to_lowercase().replace(&['-', '_', '.'], ""))
222 .collect();
223
224 let extra: HashSet<_> = entries.difference(&supported).collect();
225 let missing: HashSet<_> = supported.difference(&entries).collect();
226
227 if !(extra.is_empty() && missing.is_empty()) {
228 println!("Extra Providers: {:#?}", extra);
229 println!("Missing Providers: {:#?}", missing);
230 panic!("Mismatched README and available providers");
231 }
232 }
233
234 #[test]
235 #[cfg(feature = "all-providers")]
236 fn hafas_all_providers_up_to_date() {
237 use serde::Deserialize;
238 use std::collections::{HashMap, HashSet};
239 use toml;
240
241 #[derive(Deserialize)]
242 struct CrateCargo {
243 features: HashMap<String, Vec<String>>,
244 }
245
246 let hafas_cargo = include_str!("../../railway-provider-hafas/Cargo.toml");
247 let cargo: CrateCargo = toml::from_str(hafas_cargo).unwrap();
248
249 let hafas_supported_profiles: HashSet<_> = cargo
250 .features
251 .keys()
252 .filter_map(|s| s.strip_suffix("-profile"))
253 .map(|p| p.to_string().to_lowercase().replace(['-', '_'], ""))
254 .collect();
255 let hafas_all_profiles: HashSet<_> = cargo.features["all-profiles"]
256 .iter()
257 .map(|p| {
258 p.strip_suffix("-profile")
259 .unwrap_or_default()
260 .to_string()
261 .to_lowercase()
262 .replace(['-', '_'], "")
263 })
264 .collect();
265
266 let supported: HashSet<_> = RailwayProviderType::variants()
267 .iter()
268 .map(|p| p.to_string().to_lowercase().replace(['-', '_'], ""))
269 .collect();
270
271 let supported_hafas = supported
272 .intersection(&hafas_supported_profiles)
273 .map(|s| s.to_string())
274 .collect();
275
276 let extra: HashSet<_> = hafas_all_profiles.difference(&supported_hafas).collect();
277 let missing: HashSet<_> = supported_hafas.difference(&hafas_all_profiles).collect();
278
279 if !(extra.is_empty() && missing.is_empty()) {
280 println!("Extra Providers: {:#?}", extra);
281 println!("Missing Providers: {:#?}", missing);
282 panic!("Mismatched README and available providers");
283 }
284 }
285}