use std::borrow::Cow;
use std::fmt::{self, Debug};
use std::sync::Arc;
use super::template::Template;
use crate::{dataset::FetchError, error::Result};
pub(crate) type LocationFn = Arc<dyn Fn(usize) -> String + Send + Sync>;
#[derive(Clone)]
pub(crate) enum Locations<L> {
List(Vec<L>),
Template(Arc<Template>),
Fn { len: usize, location: LocationFn },
}
impl<L: Clone> Locations<L> {
pub(crate) fn template(template: Template, parse: impl Fn(&str) -> Result<L>) -> Result<Self> {
if template.len() > 0 {
parse(&template.render(0)?)?;
}
Ok(Self::Template(Arc::new(template)))
}
pub(crate) fn len(&self) -> usize {
match self {
Self::List(locations) => locations.len(),
Self::Template(template) => template.len(),
Self::Fn { len, .. } => *len,
}
}
pub(crate) fn get(
&self,
index: usize,
parse: impl FnOnce(&str) -> Result<L>,
) -> Result<Cow<'_, L>> {
let len = self.len();
if index >= len {
return Err(FetchError::OutOfRange { index, len }.into());
}
match self {
Self::List(locations) => Ok(Cow::Borrowed(&locations[index])),
Self::Template(template) => parse(&template.render(index)?).map(Cow::Owned),
Self::Fn { location, .. } => parse(&location(index)).map(Cow::Owned),
}
}
}
impl<L> Debug for Locations<L> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::List(locations) => write!(f, "List({} items)", locations.len()),
Self::Template(template) => write!(f, "Template({} items)", template.len()),
Self::Fn { len, .. } => write!(f, "Fn({len} items)"),
}
}
}