use std::{
path::{Path, PathBuf},
time::SystemTime,
};
use crate::{StyleLoadError, Stylesheet};
#[derive(Clone, Debug)]
pub struct LoadedStyle {
modified: SystemTime,
path: PathBuf,
style: Stylesheet,
}
impl LoadedStyle {
pub fn load(path: impl AsRef<Path>) -> Result<Self, StyleLoadError> {
let modified = path.as_ref().metadata()?.modified()?;
let style = Stylesheet::load(&path)?;
Ok(Self {
modified,
path: path.as_ref().to_path_buf(),
style,
})
}
pub fn reload(&mut self) -> Result<bool, StyleLoadError> {
let modified = self.path.metadata()?.modified()?;
let needs_reload = modified > self.modified;
if needs_reload {
self.modified = modified;
self.style = Stylesheet::load(&self.path)?;
}
Ok(needs_reload)
}
}
#[derive(Clone, Debug)]
pub enum LoadedStyleKind {
Loaded(LoadedStyle),
Inline(Stylesheet),
}
impl LoadedStyleKind {
pub fn reload(&mut self) -> Result<bool, StyleLoadError> {
match self {
Self::Loaded(loaded) => loaded.reload(),
Self::Inline(_) => Ok(false),
}
}
pub fn style(&self) -> &Stylesheet {
match self {
Self::Loaded(style) => &style.style,
Self::Inline(style) => style,
}
}
}
impl From<Stylesheet> for LoadedStyleKind {
fn from(style: Stylesheet) -> Self {
Self::Inline(style)
}
}
impl TryFrom<&str> for LoadedStyleKind {
type Error = StyleLoadError;
fn try_from(path: &str) -> Result<Self, Self::Error> {
Ok(Self::Loaded(LoadedStyle::load(path)?))
}
}
impl TryFrom<&Path> for LoadedStyleKind {
type Error = StyleLoadError;
fn try_from(path: &Path) -> Result<Self, Self::Error> {
Ok(Self::Loaded(LoadedStyle::load(path)?))
}
}
#[derive(Clone, Debug)]
pub struct StyleLoader {
styles: Vec<LoadedStyleKind>,
cache: Stylesheet,
}
impl StyleLoader {
pub fn new() -> Self {
Self {
styles: Vec::new(),
cache: Stylesheet::new(),
}
}
pub fn clear(&mut self) {
self.styles.clear();
self.cache = Stylesheet::new();
}
pub fn add_style<T: TryInto<LoadedStyleKind>>(&mut self, style: T) -> Result<(), T::Error> {
self.styles.push(style.try_into()?);
self.compute_cache();
Ok(())
}
fn compute_cache(&mut self) {
self.cache = Stylesheet::new();
for style in self.styles.iter() {
self.cache.extend(style.style().clone());
}
}
pub fn reload(&mut self) -> Result<bool, StyleLoadError> {
let mut needs_reload = false;
for style in self.styles.iter_mut() {
if style.reload()? {
needs_reload = true;
}
}
if needs_reload {
self.compute_cache();
}
Ok(needs_reload)
}
pub fn style(&self) -> &Stylesheet {
&self.cache
}
}