1use serde::de::{Error as DeError, Unexpected};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5
6use super::*;
7
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
12#[non_exhaustive]
13pub enum Provider {
14 #[default]
15 Yahoo,
17 #[cfg(feature = "polygon")]
19 Polygon,
20 #[cfg(feature = "fmp")]
22 Fmp,
23 #[cfg(feature = "alphavantage")]
25 AlphaVantage,
26 #[cfg(feature = "crypto")]
28 CoinGecko,
29 #[cfg(feature = "fred")]
31 Fred,
32 #[cfg(feature = "worldbank")]
34 WorldBank,
35 #[cfg(feature = "fiscaldata")]
37 FiscalData,
38 #[cfg(feature = "bls")]
41 Bls,
42 #[cfg(feature = "frankfurter")]
44 Frankfurter,
45 #[cfg(feature = "binance")]
47 Binance,
48 #[cfg(feature = "kraken")]
50 Kraken,
51 #[cfg(feature = "finra")]
53 Finra,
54 #[cfg(feature = "defi")]
56 DefiLlama,
57 #[cfg(feature = "gdelt")]
59 Gdelt,
60 #[cfg(feature = "cftc")]
63 Cftc,
64 #[cfg(feature = "nasdaq")]
67 Nasdaq,
68 #[cfg(feature = "wikipedia")]
71 Wikipedia,
72 #[cfg(any(feature = "housetrades", feature = "senatetrades"))]
75 CongressTrades,
76 Edgar,
78 LocalMarketCalendar,
81 LocalExchange,
84 Custom(CustomId),
95}
96
97impl Provider {
98 pub fn from_id_str(s: &str) -> Option<Self> {
102 match s {
103 "yahoo" => Some(Self::Yahoo),
104 #[cfg(feature = "polygon")]
105 "polygon" => Some(Self::Polygon),
106 #[cfg(feature = "fmp")]
107 "fmp" => Some(Self::Fmp),
108 #[cfg(feature = "alphavantage")]
109 "alphavantage" => Some(Self::AlphaVantage),
110 #[cfg(feature = "crypto")]
111 "coingecko" => Some(Self::CoinGecko),
112 #[cfg(feature = "fred")]
113 "fred" => Some(Self::Fred),
114 #[cfg(feature = "worldbank")]
115 "worldbank" => Some(Self::WorldBank),
116 #[cfg(feature = "fiscaldata")]
117 "fiscaldata" => Some(Self::FiscalData),
118 #[cfg(feature = "bls")]
119 "bls" => Some(Self::Bls),
120 #[cfg(feature = "frankfurter")]
121 "frankfurter" => Some(Self::Frankfurter),
122 #[cfg(feature = "binance")]
123 "binance" => Some(Self::Binance),
124 #[cfg(feature = "kraken")]
125 "kraken" => Some(Self::Kraken),
126 #[cfg(feature = "finra")]
127 "finra" => Some(Self::Finra),
128 #[cfg(feature = "defi")]
129 "defillama" => Some(Self::DefiLlama),
130 #[cfg(feature = "gdelt")]
131 "gdelt" => Some(Self::Gdelt),
132 #[cfg(feature = "cftc")]
133 "cftc" => Some(Self::Cftc),
134 #[cfg(feature = "nasdaq")]
135 "nasdaq" => Some(Self::Nasdaq),
136 #[cfg(feature = "wikipedia")]
137 "wikipedia" => Some(Self::Wikipedia),
138 #[cfg(any(feature = "housetrades", feature = "senatetrades"))]
139 "congresstrades" => Some(Self::CongressTrades),
140 "edgar" => Some(Self::Edgar),
141 "local_market_calendar" => Some(Self::LocalMarketCalendar),
142 "local_exchange" => Some(Self::LocalExchange),
143 other => lookup(other).map(Self::Custom),
144 }
145 }
146
147 pub fn custom(id: &'static str) -> Self {
152 Self::Custom(intern(id))
153 }
154
155 pub fn as_str(self) -> &'static str {
157 match self {
158 Self::Yahoo => "yahoo",
159 #[cfg(feature = "polygon")]
160 Self::Polygon => "polygon",
161 #[cfg(feature = "fmp")]
162 Self::Fmp => "fmp",
163 #[cfg(feature = "alphavantage")]
164 Self::AlphaVantage => "alphavantage",
165 #[cfg(feature = "crypto")]
166 Self::CoinGecko => "coingecko",
167 #[cfg(feature = "fred")]
168 Self::Fred => "fred",
169 #[cfg(feature = "worldbank")]
170 Self::WorldBank => "worldbank",
171 #[cfg(feature = "fiscaldata")]
172 Self::FiscalData => "fiscaldata",
173 #[cfg(feature = "bls")]
174 Self::Bls => "bls",
175 #[cfg(feature = "frankfurter")]
176 Self::Frankfurter => "frankfurter",
177 #[cfg(feature = "binance")]
178 Self::Binance => "binance",
179 #[cfg(feature = "kraken")]
180 Self::Kraken => "kraken",
181 #[cfg(feature = "finra")]
182 Self::Finra => "finra",
183 #[cfg(feature = "defi")]
184 Self::DefiLlama => "defillama",
185 #[cfg(feature = "gdelt")]
186 Self::Gdelt => "gdelt",
187 #[cfg(feature = "cftc")]
188 Self::Cftc => "cftc",
189 #[cfg(feature = "nasdaq")]
190 Self::Nasdaq => "nasdaq",
191 #[cfg(feature = "wikipedia")]
192 Self::Wikipedia => "wikipedia",
193 #[cfg(any(feature = "housetrades", feature = "senatetrades"))]
194 Self::CongressTrades => "congresstrades",
195 Self::Edgar => "edgar",
196 Self::LocalMarketCalendar => "local_market_calendar",
197 Self::LocalExchange => "local_exchange",
198 Self::Custom(id) => id.as_str(),
199 }
200 }
201
202 pub fn all() -> Vec<Self> {
210 let mut v = vec![Self::Yahoo];
211 #[cfg(feature = "polygon")]
212 v.push(Self::Polygon);
213 #[cfg(feature = "fmp")]
214 v.push(Self::Fmp);
215 #[cfg(feature = "alphavantage")]
216 v.push(Self::AlphaVantage);
217 #[cfg(feature = "crypto")]
218 v.push(Self::CoinGecko);
219 #[cfg(feature = "fred")]
220 v.push(Self::Fred);
221 #[cfg(feature = "worldbank")]
222 v.push(Self::WorldBank);
223 #[cfg(feature = "fiscaldata")]
224 v.push(Self::FiscalData);
225 #[cfg(feature = "bls")]
226 v.push(Self::Bls);
227 #[cfg(feature = "frankfurter")]
228 v.push(Self::Frankfurter);
229 #[cfg(feature = "binance")]
230 v.push(Self::Binance);
231 #[cfg(feature = "kraken")]
232 v.push(Self::Kraken);
233 #[cfg(feature = "finra")]
234 v.push(Self::Finra);
235 #[cfg(feature = "defi")]
236 v.push(Self::DefiLlama);
237 #[cfg(feature = "gdelt")]
238 v.push(Self::Gdelt);
239 #[cfg(feature = "cftc")]
240 v.push(Self::Cftc);
241 #[cfg(feature = "nasdaq")]
242 v.push(Self::Nasdaq);
243 #[cfg(feature = "wikipedia")]
244 v.push(Self::Wikipedia);
245 #[cfg(any(feature = "housetrades", feature = "senatetrades"))]
246 v.push(Self::CongressTrades);
247 v.push(Self::Edgar);
248 v.push(Self::LocalMarketCalendar);
249 v.push(Self::LocalExchange);
250 v
251 }
252
253 pub fn capabilities(self) -> Capability {
264 match self {
265 Self::Yahoo => yahoo::CAPS,
266 #[cfg(feature = "polygon")]
267 Self::Polygon => ProviderAdapter::capabilities(&polygon::PolygonProvider),
268 #[cfg(feature = "fmp")]
269 Self::Fmp => ProviderAdapter::capabilities(&fmp::FmpProvider),
270 #[cfg(feature = "alphavantage")]
271 Self::AlphaVantage => {
272 ProviderAdapter::capabilities(&alphavantage::AlphaVantageProvider)
273 }
274 #[cfg(feature = "crypto")]
275 Self::CoinGecko => ProviderAdapter::capabilities(&coingecko::CoinGeckoProvider),
276 #[cfg(feature = "fred")]
277 Self::Fred => ProviderAdapter::capabilities(&fred::FredProvider),
278 #[cfg(feature = "worldbank")]
279 Self::WorldBank => ProviderAdapter::capabilities(&worldbank::WorldBankProvider),
280 #[cfg(feature = "fiscaldata")]
281 Self::FiscalData => ProviderAdapter::capabilities(&fiscaldata::FiscalDataProvider),
282 #[cfg(feature = "bls")]
283 Self::Bls => ProviderAdapter::capabilities(&bls::BlsProvider),
284 #[cfg(feature = "frankfurter")]
285 Self::Frankfurter => ProviderAdapter::capabilities(&frankfurter::FrankfurterProvider),
286 #[cfg(feature = "binance")]
287 Self::Binance => ProviderAdapter::capabilities(&binance::BinanceProvider),
288 #[cfg(feature = "kraken")]
289 Self::Kraken => ProviderAdapter::capabilities(&kraken::KrakenProvider),
290 #[cfg(feature = "finra")]
291 Self::Finra => ProviderAdapter::capabilities(&finra::FinraProvider),
292 #[cfg(feature = "defi")]
293 Self::DefiLlama => ProviderAdapter::capabilities(&defillama::DefiLlamaProvider),
294 #[cfg(feature = "gdelt")]
295 Self::Gdelt => ProviderAdapter::capabilities(&gdelt::GdeltProvider),
296 #[cfg(feature = "cftc")]
297 Self::Cftc => ProviderAdapter::capabilities(&cftc::CftcProvider),
298 #[cfg(feature = "nasdaq")]
299 Self::Nasdaq => ProviderAdapter::capabilities(&nasdaq::NasdaqProvider),
300 #[cfg(feature = "wikipedia")]
301 Self::Wikipedia => ProviderAdapter::capabilities(&wikipedia::WikipediaProvider),
302 #[cfg(any(feature = "housetrades", feature = "senatetrades"))]
303 Self::CongressTrades => {
304 ProviderAdapter::capabilities(&congresstrades::CongressTradesProvider)
305 }
306 Self::Edgar => ProviderAdapter::capabilities(&edgar::EdgarProvider),
307 Self::LocalMarketCalendar => {
308 ProviderAdapter::capabilities(&market_calendar::LocalMarketCalendarProvider)
309 }
310 Self::LocalExchange => {
311 ProviderAdapter::capabilities(&local_exchanges::LocalExchangeProvider)
312 }
313 Self::Custom(_) => Capability::NONE,
314 }
315 }
316}
317
318#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
323pub struct CustomId(u16);
324
325impl CustomId {
326 pub fn as_str(self) -> &'static str {
328 self.get().unwrap_or(UNKNOWN_CUSTOM)
329 }
330
331 fn get(self) -> Option<&'static str> {
332 let ids = registry().read().ok()?;
333 ids.get(self.0 as usize).copied()
334 }
335}
336
337const UNKNOWN_CUSTOM: &str = "custom:overflow";
340
341const MAX_CUSTOM_IDS: usize = u16::MAX as usize;
344
345fn registry() -> &'static std::sync::RwLock<Vec<&'static str>> {
346 static IDS: std::sync::OnceLock<std::sync::RwLock<Vec<&'static str>>> =
347 std::sync::OnceLock::new();
348 IDS.get_or_init(|| std::sync::RwLock::new(Vec::new()))
349}
350
351fn intern(id: &'static str) -> CustomId {
352 let mut ids = match registry().write() {
353 Ok(ids) => ids,
354 Err(poisoned) => poisoned.into_inner(),
355 };
356 if let Some(index) = ids.iter().position(|existing| *existing == id) {
357 return CustomId(index as u16);
358 }
359 if ids.len() >= MAX_CUSTOM_IDS {
360 return CustomId(u16::MAX);
361 }
362 ids.push(id);
363 CustomId((ids.len() - 1) as u16)
364}
365
366fn lookup(id: &str) -> Option<CustomId> {
367 registry()
368 .read()
369 .ok()?
370 .iter()
371 .position(|existing| *existing == id)
372 .map(|index| CustomId(index as u16))
373}
374
375impl Serialize for Provider {
376 fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
377 serializer.serialize_str(self.as_str())
378 }
379}
380
381struct IdVisitor;
384
385impl serde::de::Visitor<'_> for IdVisitor {
386 type Value = Provider;
387
388 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389 f.write_str("a provider id")
390 }
391
392 fn visit_str<E: DeError>(self, v: &str) -> std::result::Result<Provider, E> {
393 Provider::from_id_str(v).ok_or_else(|| E::invalid_value(Unexpected::Str(v), &self))
394 }
395}
396
397impl<'de> Deserialize<'de> for Provider {
398 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
399 deserializer.deserialize_str(IdVisitor)
400 }
401}
402
403impl std::fmt::Display for Provider {
404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
405 f.write_str(self.as_str())
406 }
407}