use std::{collections::BTreeMap, iter::Peekable}; use log::warn; use trillium_askama::Template; #[derive(Template)] #[template(path = "home.html")] pub struct Home {} #[derive(Template)] #[template(path = "repo.html")] pub struct Repo { pub content: String, pub root: Directory, } #[derive(Clone, Template)] #[template( source = r#" {% match self %} {% when Entry::Directory(dir) %}
  • {{ dir.name|escape }}
  • {% when Entry::File(file) %}
  • {{ file.name|escape }}
  • {% endmatch %} "#, ext = "html", escape = "none" )] pub enum Entry { Directory(Directory), File(File), } #[derive(Clone)] pub struct File { pub name: String, pub path: String, pub hash: String, } #[derive(Clone, Default)] pub struct Directory { pub name: String, pub path: String, pub entries: BTreeMap, } impl Entry { fn name(&self) -> &str { match self { Entry::Directory(dir) => &dir.name, Entry::File(file) => &file.name, } } } impl PartialEq for Entry { fn eq(&self, other: &Entry) -> bool { self.name() == other.name() } } impl PartialOrd for Entry { fn partial_cmp(&self, other: &Entry) -> Option { self.name().partial_cmp(other.name()) } } impl Directory { /// Insert pub fn insert<'a>(&mut self, entry: Entry, mut path: Peekable>) { let Some(next_path_level) = path.next() else { warn!("Cannot insert entry: no more path"); return; }; if path.peek().is_some() { // Directory if let Some(parent) = self.entries.get_mut(next_path_level) { // Directory exists match parent { Entry::Directory(dir) => dir.insert(entry, path), Entry::File(_file) => { warn!("Cannot insert entry: file"); } } } else { //warn!("Cannot insert entry: not found"); // Need to create directory let mut new_dir_path = self.path.clone(); new_dir_path.push_str(next_path_level); let mut parent = Directory { name: next_path_level.into(), path: new_dir_path, entries: BTreeMap::new(), }; parent.insert(entry, path); self.entries .insert(next_path_level.into(), Entry::Directory(parent)); } } else { // File self.entries.insert(entry.name().to_string(), entry); } } pub fn find<'a>(&self, mut path: impl Iterator) -> Option<&str> { match self.entries.get(path.next()?)? { Entry::Directory(directory) => directory.find(path), Entry::File(file) => Some(&file.hash), } } }