factor out simple templates into a separate SimpleTemplateDir
there's no need to bloat TreehouseDir with that logic
This commit is contained in:
		
							parent
							
								
									b792688776
								
							
						
					
					
						commit
						550c062327
					
				
					 7 changed files with 211 additions and 156 deletions
				
			
		
							
								
								
									
										147
									
								
								src/generate.rs
									
										
									
									
									
								
							
							
						
						
									
										147
									
								
								src/generate.rs
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -4,7 +4,7 @@ mod include_static_helper;
 | 
			
		|||
mod simple_template;
 | 
			
		||||
mod tree;
 | 
			
		||||
 | 
			
		||||
use std::{collections::HashMap, fmt, ops::ControlFlow, sync::Arc};
 | 
			
		||||
use std::{ops::ControlFlow, sync::Arc};
 | 
			
		||||
 | 
			
		||||
use atom::FeedDir;
 | 
			
		||||
use dir_helper::DirHelper;
 | 
			
		||||
| 
						 | 
				
			
			@ -17,10 +17,14 @@ use crate::{
 | 
			
		|||
    config::Config,
 | 
			
		||||
    dirs::Dirs,
 | 
			
		||||
    fun::seasons::Season,
 | 
			
		||||
    generate::{
 | 
			
		||||
        simple_template::SimpleTemplateDir,
 | 
			
		||||
        tree::{DirIndex, TreehouseDir},
 | 
			
		||||
    },
 | 
			
		||||
    sources::Sources,
 | 
			
		||||
    vfs::{
 | 
			
		||||
        self, AnchoredAtExt, Cd, Content, ContentCache, Dir, DynDir, Entries, HtmlCanonicalize,
 | 
			
		||||
        MemDir, Overlay, ToDynDir, VPath, VPathBuf,
 | 
			
		||||
        self, layered_dir, AnchoredAtExt, Cd, Content, ContentCache, Dir, DynDir, Entries,
 | 
			
		||||
        HtmlCanonicalize, MemDir, Overlay, ToDynDir, VPath, VPathBuf,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,134 +80,6 @@ fn load_templates(handlebars: &mut Handlebars, dir: &dyn Dir) {
 | 
			
		|||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct TreehouseDir {
 | 
			
		||||
    dirs: Arc<Dirs>,
 | 
			
		||||
    sources: Arc<Sources>,
 | 
			
		||||
    handlebars: Arc<Handlebars<'static>>,
 | 
			
		||||
    dir_index: DirIndex,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TreehouseDir {
 | 
			
		||||
    fn new(
 | 
			
		||||
        dirs: Arc<Dirs>,
 | 
			
		||||
        sources: Arc<Sources>,
 | 
			
		||||
        handlebars: Arc<Handlebars<'static>>,
 | 
			
		||||
        dir_index: DirIndex,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            dirs,
 | 
			
		||||
            sources,
 | 
			
		||||
            handlebars,
 | 
			
		||||
            dir_index,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[instrument("TreehouseDir::dir", skip(self))]
 | 
			
		||||
    fn dir(&self, path: &VPath) -> Vec<VPathBuf> {
 | 
			
		||||
        // NOTE: This does not include simple templates, because that's not really needed right now.
 | 
			
		||||
 | 
			
		||||
        let mut index = &self.dir_index;
 | 
			
		||||
        for component in path.segments() {
 | 
			
		||||
            if let Some(child) = index.children.get(component) {
 | 
			
		||||
                index = child;
 | 
			
		||||
            } else {
 | 
			
		||||
                // There cannot possibly be any entries under an invalid path.
 | 
			
		||||
                // Bail early.
 | 
			
		||||
                return vec![];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        index
 | 
			
		||||
            .children
 | 
			
		||||
            .values()
 | 
			
		||||
            .map(|child| child.full_path.clone())
 | 
			
		||||
            .collect()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[instrument("TreehouseDir::content", skip(self))]
 | 
			
		||||
    fn content(&self, path: &VPath) -> Option<Content> {
 | 
			
		||||
        let path = if path.is_root() {
 | 
			
		||||
            VPath::new_const("index")
 | 
			
		||||
        } else {
 | 
			
		||||
            path
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        self.sources
 | 
			
		||||
            .treehouse
 | 
			
		||||
            .files_by_tree_path
 | 
			
		||||
            .get(path)
 | 
			
		||||
            .map(|&file_id| {
 | 
			
		||||
                Content::new(
 | 
			
		||||
                    "text/html",
 | 
			
		||||
                    tree::generate_or_error(&self.sources, &self.dirs, &self.handlebars, file_id)
 | 
			
		||||
                        .into(),
 | 
			
		||||
                )
 | 
			
		||||
            })
 | 
			
		||||
            .or_else(|| {
 | 
			
		||||
                if path.file_name().is_some_and(|s| !s.starts_with('_')) {
 | 
			
		||||
                    let template_name = path.with_extension("hbs");
 | 
			
		||||
                    if self.handlebars.has_template(template_name.as_str()) {
 | 
			
		||||
                        return Some(Content::new(
 | 
			
		||||
                            "text/html",
 | 
			
		||||
                            simple_template::generate_or_error(
 | 
			
		||||
                                &self.sources,
 | 
			
		||||
                                &self.handlebars,
 | 
			
		||||
                                template_name.as_str(),
 | 
			
		||||
                            )
 | 
			
		||||
                            .into(),
 | 
			
		||||
                        ));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                None
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Dir for TreehouseDir {
 | 
			
		||||
    fn query(&self, path: &VPath, query: &mut vfs::Query) {
 | 
			
		||||
        query.provide(|| Entries(self.dir(path)));
 | 
			
		||||
        query.try_provide(|| self.content(path));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for TreehouseDir {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        f.write_str("TreehouseDir")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Acceleration structure for `dir` operations on [`TreehouseDir`]s.
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
struct DirIndex {
 | 
			
		||||
    full_path: VPathBuf,
 | 
			
		||||
    children: HashMap<VPathBuf, DirIndex>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DirIndex {
 | 
			
		||||
    #[instrument(name = "DirIndex::new", skip(paths))]
 | 
			
		||||
    pub fn new<'a>(paths: impl Iterator<Item = &'a VPath>) -> Self {
 | 
			
		||||
        let mut root = DirIndex::default();
 | 
			
		||||
 | 
			
		||||
        for path in paths {
 | 
			
		||||
            let mut parent = &mut root;
 | 
			
		||||
            let mut full_path = VPath::ROOT.to_owned();
 | 
			
		||||
            for segment in path.segments() {
 | 
			
		||||
                full_path.push(segment);
 | 
			
		||||
                let child = parent
 | 
			
		||||
                    .children
 | 
			
		||||
                    .entry(segment.to_owned())
 | 
			
		||||
                    .or_insert_with(|| DirIndex {
 | 
			
		||||
                        full_path: full_path.clone(),
 | 
			
		||||
                        children: HashMap::new(),
 | 
			
		||||
                    });
 | 
			
		||||
                parent = child;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        root
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn target(dirs: Arc<Dirs>, sources: Arc<Sources>) -> DynDir {
 | 
			
		||||
    let mut handlebars = create_handlebars(&sources.config.site, dirs.static_.clone());
 | 
			
		||||
    load_templates(&mut handlebars, &dirs.template);
 | 
			
		||||
| 
						 | 
				
			
			@ -226,13 +102,16 @@ pub fn target(dirs: Arc<Dirs>, sources: Arc<Sources>) -> DynDir {
 | 
			
		|||
    );
 | 
			
		||||
 | 
			
		||||
    let dir_index = DirIndex::new(sources.treehouse.files_by_tree_path.keys().map(|x| &**x));
 | 
			
		||||
    let tree_view = TreehouseDir::new(dirs, sources, handlebars, dir_index);
 | 
			
		||||
    let treehouse_dir = layered_dir(&[
 | 
			
		||||
        TreehouseDir::new(dirs, sources.clone(), handlebars.clone(), dir_index).to_dyn(),
 | 
			
		||||
        SimpleTemplateDir::new(sources.clone(), handlebars.clone()).to_dyn(),
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    let tree_view = ContentCache::new(tree_view);
 | 
			
		||||
    let tree_view = ContentCache::new(treehouse_dir);
 | 
			
		||||
    tree_view.warm_up();
 | 
			
		||||
    let tree_view = HtmlCanonicalize::new(tree_view);
 | 
			
		||||
 | 
			
		||||
    Overlay::new(tree_view.to_dyn(), root.to_dyn())
 | 
			
		||||
    layered_dir(&[tree_view.to_dyn(), root.to_dyn()])
 | 
			
		||||
        .anchored_at(VPath::ROOT.to_owned())
 | 
			
		||||
        .to_dyn()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,8 +4,7 @@ use anyhow::Context;
 | 
			
		|||
use chrono::{DateTime, Utc};
 | 
			
		||||
use handlebars::Handlebars;
 | 
			
		||||
use serde::Serialize;
 | 
			
		||||
use tracing::{info, info_span, instrument};
 | 
			
		||||
use ulid::Ulid;
 | 
			
		||||
use tracing::{info_span, instrument};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    dirs::Dirs,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,30 +1,70 @@
 | 
			
		|||
use std::{fmt, sync::Arc};
 | 
			
		||||
 | 
			
		||||
use anyhow::Context;
 | 
			
		||||
use handlebars::Handlebars;
 | 
			
		||||
use tracing::instrument;
 | 
			
		||||
 | 
			
		||||
use crate::sources::Sources;
 | 
			
		||||
use crate::{
 | 
			
		||||
    sources::Sources,
 | 
			
		||||
    vfs::{Content, Dir, Query, VPath},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::BaseTemplateData;
 | 
			
		||||
 | 
			
		||||
#[instrument(name = "simple_template::generate", skip(sources, handlebars))]
 | 
			
		||||
pub fn generate(
 | 
			
		||||
    sources: &Sources,
 | 
			
		||||
    handlebars: &Handlebars,
 | 
			
		||||
    template_name: &str,
 | 
			
		||||
) -> anyhow::Result<String> {
 | 
			
		||||
    let base_template_data = BaseTemplateData::new(sources);
 | 
			
		||||
    handlebars
 | 
			
		||||
        .render(template_name, &base_template_data)
 | 
			
		||||
        .context("failed to render template")
 | 
			
		||||
pub struct SimpleTemplateDir {
 | 
			
		||||
    sources: Arc<Sources>,
 | 
			
		||||
    handlebars: Arc<Handlebars<'static>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn generate_or_error(
 | 
			
		||||
    sources: &Sources,
 | 
			
		||||
    handlebars: &Handlebars,
 | 
			
		||||
    template_name: &str,
 | 
			
		||||
) -> String {
 | 
			
		||||
    match generate(sources, handlebars, template_name) {
 | 
			
		||||
impl SimpleTemplateDir {
 | 
			
		||||
    pub fn new(sources: Arc<Sources>, handlebars: Arc<Handlebars<'static>>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            sources,
 | 
			
		||||
            handlebars,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[instrument(name = "simple_template::generate", skip(self))]
 | 
			
		||||
    fn generate(&self, template_name: &str) -> anyhow::Result<String> {
 | 
			
		||||
        let base_template_data = BaseTemplateData::new(&self.sources);
 | 
			
		||||
        self.handlebars
 | 
			
		||||
            .render(template_name, &base_template_data)
 | 
			
		||||
            .context("failed to render template")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn generate_or_error(&self, template_name: &str) -> String {
 | 
			
		||||
        match self.generate(template_name) {
 | 
			
		||||
            Ok(html) => html,
 | 
			
		||||
            Err(error) => format!("error: {error:?}"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[instrument("TreehouseDir::content", skip(self))]
 | 
			
		||||
    fn content(&self, path: &VPath) -> Option<Content> {
 | 
			
		||||
        if path.file_name().is_some_and(|s| !s.starts_with('_')) {
 | 
			
		||||
            let template_name = path.with_extension("hbs");
 | 
			
		||||
            if self.handlebars.has_template(template_name.as_str()) {
 | 
			
		||||
                return Some(Content::new(
 | 
			
		||||
                    "text/html",
 | 
			
		||||
                    self.generate_or_error(template_name.as_str()).into(),
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Dir for SimpleTemplateDir {
 | 
			
		||||
    fn query(&self, path: &VPath, query: &mut Query) {
 | 
			
		||||
        // NOTE: An implementation of Entries is not currently provided, because SimpleTemplateDir
 | 
			
		||||
        // isn't used enough to need one.
 | 
			
		||||
        query.try_provide(|| self.content(path));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for SimpleTemplateDir {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        f.write_str("SimpleTemplateDir")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
use std::{collections::HashMap, fmt, sync::Arc};
 | 
			
		||||
 | 
			
		||||
use anyhow::{ensure, Context};
 | 
			
		||||
use handlebars::Handlebars;
 | 
			
		||||
use serde::Serialize;
 | 
			
		||||
| 
						 | 
				
			
			@ -5,10 +7,11 @@ use tracing::{info_span, instrument};
 | 
			
		|||
 | 
			
		||||
use crate::{
 | 
			
		||||
    dirs::Dirs,
 | 
			
		||||
    generate::BaseTemplateData,
 | 
			
		||||
    generate::{simple_template, BaseTemplateData},
 | 
			
		||||
    html::{breadcrumbs::breadcrumbs_to_html, tree},
 | 
			
		||||
    sources::Sources,
 | 
			
		||||
    state::FileId,
 | 
			
		||||
    vfs::{self, Content, Dir, Entries, VPath, VPathBuf},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
| 
						 | 
				
			
			@ -109,3 +112,113 @@ pub fn generate_or_error(
 | 
			
		|||
        Err(error) => format!("error: {error:?}"),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TreehouseDir {
 | 
			
		||||
    dirs: Arc<Dirs>,
 | 
			
		||||
    sources: Arc<Sources>,
 | 
			
		||||
    handlebars: Arc<Handlebars<'static>>,
 | 
			
		||||
    dir_index: DirIndex,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TreehouseDir {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        dirs: Arc<Dirs>,
 | 
			
		||||
        sources: Arc<Sources>,
 | 
			
		||||
        handlebars: Arc<Handlebars<'static>>,
 | 
			
		||||
        dir_index: DirIndex,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            dirs,
 | 
			
		||||
            sources,
 | 
			
		||||
            handlebars,
 | 
			
		||||
            dir_index,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[instrument("TreehouseDir::dir", skip(self))]
 | 
			
		||||
    fn dir(&self, path: &VPath) -> Vec<VPathBuf> {
 | 
			
		||||
        // NOTE: This does not include simple templates, because that's not really needed right now.
 | 
			
		||||
 | 
			
		||||
        let mut index = &self.dir_index;
 | 
			
		||||
        for component in path.segments() {
 | 
			
		||||
            if let Some(child) = index.children.get(component) {
 | 
			
		||||
                index = child;
 | 
			
		||||
            } else {
 | 
			
		||||
                // There cannot possibly be any entries under an invalid path.
 | 
			
		||||
                // Bail early.
 | 
			
		||||
                return vec![];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        index
 | 
			
		||||
            .children
 | 
			
		||||
            .values()
 | 
			
		||||
            .map(|child| child.full_path.clone())
 | 
			
		||||
            .collect()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[instrument("TreehouseDir::content", skip(self))]
 | 
			
		||||
    fn content(&self, path: &VPath) -> Option<Content> {
 | 
			
		||||
        let path = if path.is_root() {
 | 
			
		||||
            VPath::new_const("index")
 | 
			
		||||
        } else {
 | 
			
		||||
            path
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        self.sources
 | 
			
		||||
            .treehouse
 | 
			
		||||
            .files_by_tree_path
 | 
			
		||||
            .get(path)
 | 
			
		||||
            .map(|&file_id| {
 | 
			
		||||
                Content::new(
 | 
			
		||||
                    "text/html",
 | 
			
		||||
                    generate_or_error(&self.sources, &self.dirs, &self.handlebars, file_id).into(),
 | 
			
		||||
                )
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Dir for TreehouseDir {
 | 
			
		||||
    fn query(&self, path: &VPath, query: &mut vfs::Query) {
 | 
			
		||||
        query.provide(|| Entries(self.dir(path)));
 | 
			
		||||
        query.try_provide(|| self.content(path));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for TreehouseDir {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        f.write_str("TreehouseDir")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Acceleration structure for `dir` operations on [`TreehouseDir`]s.
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
pub struct DirIndex {
 | 
			
		||||
    full_path: VPathBuf,
 | 
			
		||||
    children: HashMap<VPathBuf, DirIndex>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DirIndex {
 | 
			
		||||
    #[instrument(name = "DirIndex::new", skip(paths))]
 | 
			
		||||
    pub fn new<'a>(paths: impl Iterator<Item = &'a VPath>) -> Self {
 | 
			
		||||
        let mut root = DirIndex::default();
 | 
			
		||||
 | 
			
		||||
        for path in paths {
 | 
			
		||||
            let mut parent = &mut root;
 | 
			
		||||
            let mut full_path = VPath::ROOT.to_owned();
 | 
			
		||||
            for segment in path.segments() {
 | 
			
		||||
                full_path.push(segment);
 | 
			
		||||
                let child = parent
 | 
			
		||||
                    .children
 | 
			
		||||
                    .entry(segment.to_owned())
 | 
			
		||||
                    .or_insert_with(|| DirIndex {
 | 
			
		||||
                        full_path: full_path.clone(),
 | 
			
		||||
                        children: HashMap::new(),
 | 
			
		||||
                    });
 | 
			
		||||
                parent = child;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        root
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -168,6 +168,12 @@ impl<'a> dyn Erased<'a> + 'a {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Dir for () {
 | 
			
		||||
    fn query(&self, _path: &VPath, _query: &mut Query) {
 | 
			
		||||
        // Noop implementation.
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> Dir for &T
 | 
			
		||||
where
 | 
			
		||||
    T: Dir,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ use core::fmt;
 | 
			
		|||
 | 
			
		||||
use super::{Dir, Query, VPath};
 | 
			
		||||
 | 
			
		||||
/// This Dir exists to serve as a compatibility layer for very old links that end with .html.
 | 
			
		||||
pub struct HtmlCanonicalize<T> {
 | 
			
		||||
    inner: T,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,8 @@ use std::fmt;
 | 
			
		|||
 | 
			
		||||
use tracing::instrument;
 | 
			
		||||
 | 
			
		||||
use crate::vfs::ToDynDir;
 | 
			
		||||
 | 
			
		||||
use super::{entries, Dir, DynDir, Entries, Query, VPath, VPathBuf};
 | 
			
		||||
 | 
			
		||||
pub struct Overlay {
 | 
			
		||||
| 
						 | 
				
			
			@ -38,3 +40,18 @@ impl fmt::Debug for Overlay {
 | 
			
		|||
        write!(f, "Overlay({:?}, {:?})", self.base, self.overlay)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn layered_dir(layers: &[DynDir]) -> DynDir {
 | 
			
		||||
    match layers {
 | 
			
		||||
        [] => ().to_dyn(),
 | 
			
		||||
        [dir] => dir.clone(),
 | 
			
		||||
        [left, right] => Overlay::new(left.clone(), right.clone()).to_dyn(),
 | 
			
		||||
        [left, right, rest @ ..] => {
 | 
			
		||||
            let mut overlay = Overlay::new(left.clone(), right.clone());
 | 
			
		||||
            for dir in rest {
 | 
			
		||||
                overlay = Overlay::new(overlay.to_dyn(), dir.clone());
 | 
			
		||||
            }
 | 
			
		||||
            overlay.to_dyn()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue