use super::{Backend, BoxedBackend, BoxedConnector};
use crate::{Error, Result, ToUrl};
use log::{error, info};
use std::sync::{Arc, RwLock};
type Backends = Arc<RwLock<Vec<BoxedBackend>>>;
#[derive(Clone)]
pub struct Manager {
backends: Backends,
}
impl Default for Manager {
fn default() -> Self {
Self {
backends: Arc::new(RwLock::new(Vec::default())),
}
}
}
impl Manager {
pub fn register(&self, backend: impl Backend + 'static) -> Result<()> {
self.with_mut(|backends| {
let name = backend.name();
if backends.iter().any(|backend| backend.name() == name) {
error!("Attempt to register backend \"{}\" twice", name);
return Err(Error::AlreadyRegistered(name.into()));
}
info!("Registering backend \"{}\"", name);
backends.push(Box::new(backend));
Ok(())
})
}
pub fn create(&self, url: impl ToUrl) -> Result<BoxedConnector> {
let url = url.to_url()?;
self.with(|backends| {
backends
.iter()
.filter_map(|backend| backend.connector(&url))
.next()
.ok_or_else(|| {
error!("No backends which can handle URL {}", url);
url.into()
})
})
}
fn with_raw<R>(&self, func: impl FnOnce(Backends) -> R) -> R {
func(self.backends.clone())
}
fn with<R>(&self, func: impl FnOnce(&[BoxedBackend]) -> R) -> R {
self.with_raw(|backends: Backends| {
let backends = backends.read().unwrap();
func(&backends)
})
}
fn with_mut<R>(&self, func: impl FnOnce(&mut Vec<BoxedBackend>) -> R) -> R {
self.with_raw(|backends: Backends| {
let mut backends = backends.write().unwrap();
func(&mut backends)
})
}
}