use crate::errors::Result;
use crate::map::Map;
use crate::path;
use crate::value::{Value, ValueKind};
#[cfg(feature = "async")]
use async_trait::async_trait;
use std::fmt::Debug;
use std::str::FromStr;
pub trait Source: Debug {
fn clone_into_box(&self) -> Box<dyn Source + Send + Sync>;
fn collect(&self) -> Result<Map<String, Value>>;
fn collect_to(&self, cache: &mut Value) -> Result<()> {
self.collect()?.iter().for_each(|(key, val)| set_value(cache, key, val));
Ok(())
}
}
fn set_value(cache: &mut Value, key: &str, value: &Value) {
match path::Expression::from_str(key) {
Ok(expr) => expr.set(cache, value.clone()),
_ => path::Expression::Identifier(key.to_string()).set(cache, value.clone()),
}
}
#[cfg(feature = "async")]
#[async_trait]
pub trait AsyncSource: Debug + Sync {
async fn collect(&self) -> Result<Map<String, Value>>;
async fn collect_to(&self, cache: &mut Value) -> Result<()> {
self.collect().await?.iter().for_each(|(key, val)| set_value(cache, key, val));
Ok(())
}
}
#[cfg(feature = "async")]
impl Clone for Box<dyn AsyncSource + Send + Sync> {
fn clone(&self) -> Self {
self.to_owned()
}
}
impl Clone for Box<dyn Source + Send + Sync> {
fn clone(&self) -> Self {
self.clone_into_box()
}
}
impl Source for Vec<Box<dyn Source + Send + Sync>> {
fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
Box::new((*self).clone())
}
fn collect(&self) -> Result<Map<String, Value>> {
let mut cache: Value = Map::<String, Value>::new().into();
for source in self {
source.collect_to(&mut cache)?;
}
if let ValueKind::Table(table) = cache.kind {
Ok(table)
} else {
unreachable!();
}
}
}
impl Source for [Box<dyn Source + Send + Sync>] {
fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
Box::new(self.to_owned())
}
fn collect(&self) -> Result<Map<String, Value>> {
let mut cache: Value = Map::<String, Value>::new().into();
for source in self {
source.collect_to(&mut cache)?;
}
if let ValueKind::Table(table) = cache.kind {
Ok(table)
} else {
unreachable!();
}
}
}
impl<T> Source for Vec<T>
where
T: Source + Sync + Send + Clone + 'static,
{
fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
Box::new((*self).clone())
}
fn collect(&self) -> Result<Map<String, Value>> {
let mut cache: Value = Map::<String, Value>::new().into();
for source in self {
source.collect_to(&mut cache)?;
}
if let ValueKind::Table(table) = cache.kind {
Ok(table)
} else {
unreachable!();
}
}
}