use crate::provider::BoxedBlockingProvider;
#[cfg(feature = "tokio")]
use crate::provider::BoxedProvider;
use crate::types::{BuiltinProvider, IpVersion, Protocol};
use std::time::Duration;
#[derive(Debug, Clone, Copy, Default)]
#[non_exhaustive]
pub enum Strategy {
#[default]
First,
Race,
Consensus {
min_agree: usize,
},
}
pub struct Config {
pub(crate) blocking_providers: Vec<BoxedBlockingProvider>,
#[cfg(feature = "tokio")]
pub(crate) providers: Vec<BoxedProvider>,
pub(crate) timeout: Duration,
pub(crate) version: IpVersion,
pub(crate) strategy: Strategy,
}
impl Default for Config {
fn default() -> Self {
Self::builder().build()
}
}
impl Config {
pub fn builder() -> ConfigBuilder {
ConfigBuilder::new()
}
}
pub struct ConfigBuilder {
#[cfg(feature = "tokio")]
custom_providers: Vec<BoxedProvider>,
custom_blocking_providers: Vec<BoxedBlockingProvider>,
timeout: Duration,
version: IpVersion,
strategy: Strategy,
provider_filter: Option<ProviderFilter>,
}
#[derive(Clone)]
enum ProviderFilter {
Protocols(Vec<Protocol>),
Select(Vec<BuiltinProvider>),
}
impl ConfigBuilder {
pub fn new() -> Self {
Self {
#[cfg(feature = "tokio")]
custom_providers: Vec::new(),
custom_blocking_providers: Vec::new(),
timeout: Duration::from_secs(10),
version: IpVersion::Any,
strategy: Strategy::First,
provider_filter: None,
}
}
pub fn protocols(mut self, protocols: &[Protocol]) -> Self {
self.provider_filter = Some(ProviderFilter::Protocols(protocols.to_vec()));
self
}
pub fn providers(mut self, providers: &[BuiltinProvider]) -> Self {
self.provider_filter = Some(ProviderFilter::Select(providers.to_vec()));
self
}
#[cfg(feature = "tokio")]
pub fn add_provider(mut self, provider: BoxedProvider) -> Self {
self.custom_providers.push(provider);
self
}
pub fn add_blocking_provider(mut self, provider: BoxedBlockingProvider) -> Self {
self.custom_blocking_providers.push(provider);
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn version(mut self, version: IpVersion) -> Self {
self.version = version;
self
}
pub fn strategy(mut self, strategy: Strategy) -> Self {
self.strategy = match strategy {
Strategy::Consensus { min_agree } => Strategy::Consensus {
min_agree: min_agree.max(2),
},
other => other,
};
self
}
pub fn build(mut self) -> Config {
let filter = self.provider_filter.take();
#[cfg(feature = "tokio")]
let has_custom_providers =
!self.custom_blocking_providers.is_empty() || !self.custom_providers.is_empty();
#[cfg(not(feature = "tokio"))]
let has_custom_providers = !self.custom_blocking_providers.is_empty();
let mut blocking_providers: Vec<BoxedBlockingProvider> = match &filter {
Some(ProviderFilter::Protocols(protocols)) => BuiltinProvider::ALL
.iter()
.filter(|p| protocols.contains(&p.protocol()))
.map(|p| p.to_boxed_blocking())
.collect(),
Some(ProviderFilter::Select(selected)) => {
selected.iter().map(|p| p.to_boxed_blocking()).collect()
}
None if !has_custom_providers => BuiltinProvider::ALL
.iter()
.map(|p| p.to_boxed_blocking())
.collect(),
None => Vec::new(),
};
blocking_providers.append(&mut self.custom_blocking_providers);
#[cfg(feature = "tokio")]
let mut providers: Vec<BoxedProvider> = match filter {
Some(ProviderFilter::Protocols(protocols)) => BuiltinProvider::ALL
.iter()
.filter(|p| protocols.contains(&p.protocol()))
.map(|p| p.to_boxed())
.collect(),
Some(ProviderFilter::Select(selected)) => {
selected.into_iter().map(|p| p.to_boxed()).collect()
}
None if !has_custom_providers => {
BuiltinProvider::ALL.iter().map(|p| p.to_boxed()).collect()
}
None => Vec::new(),
};
#[cfg(feature = "tokio")]
providers.append(&mut self.custom_providers);
Config {
blocking_providers,
#[cfg(feature = "tokio")]
providers,
timeout: self.timeout,
version: self.version,
strategy: self.strategy,
}
}
}
impl Default for ConfigBuilder {
fn default() -> Self {
Self::new()
}
}