Skip to main content

finance_query/providers/adapter/
dispatch.rs

1//! [`ProviderAdapter`]: the accessors dispatch walks to reach a capability.
2
3use super::super::Capability;
4use crate::error::Result;
5
6use super::ProviderCore;
7use super::equity::*;
8use super::markets::*;
9
10/// A configured provider as seen by [`crate::ProviderSet`] dispatch: lifecycle
11/// plus one `as_*` accessor per capability. Override an accessor to
12/// `Some(self)` for each capability trait the provider implements.
13///
14/// [`capabilities`](Self::capabilities) is derived from which accessors are
15/// overridden, so a provider cannot advertise a capability it does not serve.
16#[async_trait::async_trait]
17pub trait ProviderAdapter: ProviderCore {
18    /// Initialize this provider. Called once during construction.
19    async fn initialize(&self) -> Result<()> {
20        Ok(())
21    }
22
23    /// Best-effort estimate of remaining rate-limit budget — tokens
24    /// currently available in this provider's own token bucket, for
25    /// [`crate::Providers::health`]. Peeking never consumes a
26    /// token.
27    ///
28    /// `None` by default: providers with no local rate limiter to peek (e.g.
29    /// Yahoo) or whose singleton hasn't been initialized yet return `None`
30    /// rather than a misleading number.
31    fn rate_limit_remaining(&self) -> Option<f64> {
32        None
33    }
34
35    /// Override to `Some(self)` to serve [`crate::Capability::QUOTE`].
36    fn as_quote(&self) -> Option<&dyn QuoteProvider> {
37        None
38    }
39    /// Override to `Some(self)` to serve [`crate::Capability::CHART`].
40    fn as_chart(&self) -> Option<&dyn ChartProvider> {
41        None
42    }
43    /// Override to `Some(self)` to serve [`crate::Capability::FUNDAMENTALS`].
44    fn as_fundamentals(&self) -> Option<&dyn FundamentalsProvider> {
45        None
46    }
47    /// Override to `Some(self)` to serve [`crate::Capability::CORPORATE`].
48    fn as_corporate(&self) -> Option<&dyn CorporateProvider> {
49        None
50    }
51    /// Override to `Some(self)` to serve [`crate::Capability::OPTIONS`].
52    fn as_options(&self) -> Option<&dyn OptionsProvider> {
53        None
54    }
55    /// Override to `Some(self)` to serve [`crate::Capability::FILINGS`].
56    fn as_filings(&self) -> Option<&dyn FilingsProvider> {
57        None
58    }
59    /// Override to `Some(self)` to serve [`crate::Capability::DISCOVERY`].
60    fn as_discovery(&self) -> Option<&dyn DiscoveryProvider> {
61        None
62    }
63    /// Override to `Some(self)` to serve [`crate::Capability::CALENDAR`].
64    fn as_calendar(&self) -> Option<&dyn CalendarProvider> {
65        None
66    }
67    /// Override to `Some(self)` to serve [`crate::Capability::MARKET`].
68    fn as_market(&self) -> Option<&dyn MarketProvider> {
69        None
70    }
71    /// Override to `Some(self)` to serve [`crate::Capability::CRYPTO`].
72    fn as_crypto(&self) -> Option<&dyn CryptoProvider> {
73        None
74    }
75    /// Override to `Some(self)` to serve [`crate::Capability::ECONOMIC`].
76    fn as_economic(&self) -> Option<&dyn EconomicProvider> {
77        None
78    }
79    /// Override to `Some(self)` to serve [`crate::Capability::FOREX`].
80    fn as_forex(&self) -> Option<&dyn ForexProvider> {
81        None
82    }
83    /// Override to `Some(self)` to serve [`crate::Capability::INDICES`].
84    fn as_indices(&self) -> Option<&dyn IndicesProvider> {
85        None
86    }
87    /// Override to `Some(self)` to serve [`crate::Capability::FUTURES`].
88    fn as_futures(&self) -> Option<&dyn FuturesProvider> {
89        None
90    }
91    /// Override to `Some(self)` to serve [`crate::Capability::COMMODITIES`].
92    fn as_commodities(&self) -> Option<&dyn CommoditiesProvider> {
93        None
94    }
95
96    /// Derived from the accessors — a provider supports a capability iff the
97    /// matching `as_*` accessor returns `Some`. Never override.
98    fn capabilities(&self) -> Capability {
99        let mut caps = Capability::NONE;
100        if self.as_quote().is_some() {
101            caps = caps | Capability::QUOTE;
102        }
103        if self.as_chart().is_some() {
104            caps = caps | Capability::CHART;
105        }
106        if self.as_fundamentals().is_some() {
107            caps = caps | Capability::FUNDAMENTALS;
108        }
109        if self.as_corporate().is_some() {
110            caps = caps | Capability::CORPORATE;
111        }
112        if self.as_options().is_some() {
113            caps = caps | Capability::OPTIONS;
114        }
115        if self.as_filings().is_some() {
116            caps = caps | Capability::FILINGS;
117        }
118        if self.as_market().is_some() {
119            caps = caps | Capability::MARKET;
120        }
121        if self.as_discovery().is_some() {
122            caps = caps | Capability::DISCOVERY;
123        }
124        if self.as_calendar().is_some() {
125            caps = caps | Capability::CALENDAR;
126        }
127        #[cfg(any(
128            feature = "alphavantage",
129            feature = "binance",
130            feature = "crypto",
131            feature = "defi",
132            feature = "fmp",
133            feature = "gdelt",
134            feature = "kraken",
135            feature = "polygon"
136        ))]
137        if self.as_crypto().is_some() {
138            caps = caps | Capability::CRYPTO;
139        }
140        #[cfg(any(
141            feature = "alphavantage",
142            feature = "bls",
143            feature = "fiscaldata",
144            feature = "fred",
145            feature = "polygon",
146            feature = "worldbank"
147        ))]
148        if self.as_economic().is_some() {
149            caps = caps | Capability::ECONOMIC;
150        }
151        #[cfg(any(
152            feature = "alphavantage",
153            feature = "fmp",
154            feature = "frankfurter",
155            feature = "gdelt",
156            feature = "polygon"
157        ))]
158        if self.as_forex().is_some() {
159            caps = caps | Capability::FOREX;
160        }
161        if self.as_indices().is_some() {
162            caps = caps | Capability::INDICES;
163        }
164        if self.as_futures().is_some() {
165            caps = caps | Capability::FUTURES;
166        }
167        if self.as_commodities().is_some() {
168            caps = caps | Capability::COMMODITIES;
169        }
170        caps
171    }
172}