enginerenderer 0.0.1

A zero-dependency offline rendering engine in pure Rust — CPU path tracing, BVH acceleration, 16-band spectral rendering, PBR materials, animation & video export.
Documentation
use std::path::{Path, PathBuf};
use std::time::SystemTime;

pub struct WatchedAsset {
    pub path: PathBuf,
    pub last_modified: SystemTime,
}

impl WatchedAsset {
    pub fn new(path: impl Into<PathBuf>) -> Option<Self> {
        let path = path.into();
        let last_modified = std::fs::metadata(&path).ok()?.modified().ok()?;
        Some(Self {
            path,
            last_modified,
        })
    }

    pub fn has_changed(&self) -> bool {
        std::fs::metadata(&self.path)
            .ok()
            .and_then(|m| m.modified().ok())
            .map(|t| t > self.last_modified)
            .unwrap_or(false)
    }

    pub fn update_timestamp(&mut self) {
        if let Some(t) = std::fs::metadata(&self.path)
            .ok()
            .and_then(|m| m.modified().ok())
        {
            self.last_modified = t;
        }
    }
}

pub struct HotReloader {
    watched: Vec<WatchedAsset>,
}

impl HotReloader {
    pub fn new() -> Self {
        Self {
            watched: Vec::new(),
        }
    }

    pub fn watch(&mut self, path: impl Into<PathBuf>) {
        let path = path.into();
        if let Some(asset) = WatchedAsset::new(&path) {
            self.watched.push(asset);
        }
    }

    pub fn poll(&mut self) -> Vec<PathBuf> {
        let mut changed = Vec::new();
        for asset in &mut self.watched {
            if asset.has_changed() {
                changed.push(asset.path.clone());
                asset.update_timestamp();
            }
        }
        changed
    }

    pub fn watch_count(&self) -> usize {
        self.watched.len()
    }

    pub fn watched_paths(&self) -> impl Iterator<Item = &Path> {
        self.watched.iter().map(|a| a.path.as_path())
    }
}

impl std::fmt::Debug for HotReloader {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("HotReloader")
            .field("watch_count", &self.watched.len())
            .finish()
    }
}