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    /// Whether requests go to an origin set with
36    /// [`ProvidersBuilder::endpoint`](crate::ProvidersBuilder::endpoint).
37    ///
38    /// `false` by default, and the builder rejects an endpoint for a provider
39    /// that would ignore it.
40    fn accepts_endpoint(&self) -> bool {
41        false
42    }
43
44    /// Whether this provider's API-key budget follows
45    /// [`ProvidersBuilder::requests_per_minute`](crate::ProvidersBuilder::requests_per_minute).
46    ///
47    /// `false` by default, and the builder rejects a budget for a provider that
48    /// would ignore it.
49    fn accepts_request_budget(&self) -> bool {
50        false
51    }
52
53    /// Override to `Some(self)` to serve [`crate::Capability::QUOTE`].
54    fn as_quote(&self) -> Option<&dyn QuoteProvider> {
55        None
56    }
57    /// Override to `Some(self)` to serve [`crate::Capability::CHART`].
58    fn as_chart(&self) -> Option<&dyn ChartProvider> {
59        None
60    }
61    /// Override to `Some(self)` to serve [`crate::Capability::FUNDAMENTALS`].
62    fn as_fundamentals(&self) -> Option<&dyn FundamentalsProvider> {
63        None
64    }
65    /// Override to `Some(self)` to serve [`crate::Capability::CORPORATE`].
66    fn as_corporate(&self) -> Option<&dyn CorporateProvider> {
67        None
68    }
69    /// Override to `Some(self)` to serve [`crate::Capability::OPTIONS`].
70    fn as_options(&self) -> Option<&dyn OptionsProvider> {
71        None
72    }
73    /// Override to `Some(self)` to serve [`crate::Capability::FILINGS`].
74    fn as_filings(&self) -> Option<&dyn FilingsProvider> {
75        None
76    }
77    /// Override to `Some(self)` to serve [`crate::Capability::DISCOVERY`].
78    fn as_discovery(&self) -> Option<&dyn DiscoveryProvider> {
79        None
80    }
81    /// Override to `Some(self)` to serve [`crate::Capability::CALENDAR`].
82    fn as_calendar(&self) -> Option<&dyn CalendarProvider> {
83        None
84    }
85    /// Override to `Some(self)` to serve [`crate::Capability::MARKET`].
86    fn as_market(&self) -> Option<&dyn MarketProvider> {
87        None
88    }
89    /// Override to `Some(self)` to serve [`crate::Capability::CRYPTO`].
90    fn as_crypto(&self) -> Option<&dyn CryptoProvider> {
91        None
92    }
93    /// Override to `Some(self)` to serve [`crate::Capability::ECONOMIC`].
94    fn as_economic(&self) -> Option<&dyn EconomicProvider> {
95        None
96    }
97    /// Override to `Some(self)` to serve [`crate::Capability::FOREX`].
98    fn as_forex(&self) -> Option<&dyn ForexProvider> {
99        None
100    }
101    /// Override to `Some(self)` to serve [`crate::Capability::INDICES`].
102    fn as_indices(&self) -> Option<&dyn IndicesProvider> {
103        None
104    }
105    /// Override to `Some(self)` to serve [`crate::Capability::FUTURES`].
106    fn as_futures(&self) -> Option<&dyn FuturesProvider> {
107        None
108    }
109    /// Override to `Some(self)` to serve [`crate::Capability::COMMODITIES`].
110    fn as_commodities(&self) -> Option<&dyn CommoditiesProvider> {
111        None
112    }
113
114    /// Derived from the accessors — a provider supports a capability iff the
115    /// matching `as_*` accessor returns `Some`. Never override.
116    fn capabilities(&self) -> Capability {
117        let mut caps = Capability::NONE;
118        if self.as_quote().is_some() {
119            caps = caps | Capability::QUOTE;
120        }
121        if self.as_chart().is_some() {
122            caps = caps | Capability::CHART;
123        }
124        if self.as_fundamentals().is_some() {
125            caps = caps | Capability::FUNDAMENTALS;
126        }
127        if self.as_corporate().is_some() {
128            caps = caps | Capability::CORPORATE;
129        }
130        if self.as_options().is_some() {
131            caps = caps | Capability::OPTIONS;
132        }
133        if self.as_filings().is_some() {
134            caps = caps | Capability::FILINGS;
135        }
136        if self.as_market().is_some() {
137            caps = caps | Capability::MARKET;
138        }
139        if self.as_discovery().is_some() {
140            caps = caps | Capability::DISCOVERY;
141        }
142        if self.as_calendar().is_some() {
143            caps = caps | Capability::CALENDAR;
144        }
145        #[cfg(any(
146            feature = "alphavantage",
147            feature = "binance",
148            feature = "crypto",
149            feature = "defi",
150            feature = "fmp",
151            feature = "gdelt",
152            feature = "kraken",
153            feature = "polygon"
154        ))]
155        if self.as_crypto().is_some() {
156            caps = caps | Capability::CRYPTO;
157        }
158        #[cfg(any(
159            feature = "alphavantage",
160            feature = "bls",
161            feature = "fiscaldata",
162            feature = "fred",
163            feature = "polygon",
164            feature = "worldbank"
165        ))]
166        if self.as_economic().is_some() {
167            caps = caps | Capability::ECONOMIC;
168        }
169        #[cfg(any(
170            feature = "alphavantage",
171            feature = "fmp",
172            feature = "frankfurter",
173            feature = "gdelt",
174            feature = "polygon"
175        ))]
176        if self.as_forex().is_some() {
177            caps = caps | Capability::FOREX;
178        }
179        if self.as_indices().is_some() {
180            caps = caps | Capability::INDICES;
181        }
182        if self.as_futures().is_some() {
183            caps = caps | Capability::FUTURES;
184        }
185        if self.as_commodities().is_some() {
186            caps = caps | Capability::COMMODITIES;
187        }
188        caps
189    }
190}