diff --git a/src/pipeline.rs b/src/pipeline.rs index 9bae18b..a1ec517 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -11,6 +11,12 @@ pub struct Parallel(S); /// An adapter to map the result of the pipeline pub struct Map(S, Box T + Send + Sync>); +/// An adapter to dynamically construct the next step mapper depending on the previous one +pub struct Construct, T>( + S1, + Box (T, S2) + Send + Sync>, +); + /// A generic wrapper for processing pipelines pub struct ProcessingPipeline( Box>, @@ -87,10 +93,41 @@ impl ProcessingStep for Map { async fn process(&self, input: Self::Input) -> Result { let inner_result = self.0.process(input).await?; + Ok(self.1(inner_result)) } } +pub trait ProcessingConstruct: ProcessingStep + Sized { + fn construct< + F: Fn(Self::Output) -> (T, S) + Send + Sync + 'static, + S: ProcessingStep, + T: Send + Sync, + >( + self, + construct_fn: F, + ) -> Construct { + Construct(self, Box::new(construct_fn)) + } +} + +impl ProcessingConstruct for S {} + +#[async_trait] +impl, T: Send + Sync> ProcessingStep + for Construct +{ + type Input = S1::Input; + type Output = S2::Output; + + async fn process(&self, input: Self::Input) -> Result { + let inner_output = self.0.process(input).await?; + let (new_input, step) = self.1(inner_output); + + step.process(new_input).await + } +} + #[async_trait] impl ProcessingStep for ProcessingPipeline { type Input = I; diff --git a/src/rendering/load_dir_content.rs b/src/rendering/load_dir_content.rs index f29b346..dddc086 100644 --- a/src/rendering/load_dir_content.rs +++ b/src/rendering/load_dir_content.rs @@ -10,7 +10,7 @@ pub struct LoadDirContent; #[async_trait] impl ProcessingStep for LoadDirContent { type Input = FolderData; - type Output = Vec<(PathBuf, String)>; + type Output = (Vec, String); #[tracing::instrument(name = "load dir", level = "trace", skip_all)] async fn process(&self, input: Self::Input) -> Result { @@ -27,10 +27,6 @@ impl ProcessingStep for LoadDirContent { .to_owned() .unwrap_or(dir_name.into()); - Ok(input - .pages - .into_iter() - .map(|p| (p, default_template.clone())) - .collect()) + Ok((input.pages, default_template)) } } diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index 0073e79..950c1ff 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -49,19 +49,25 @@ impl ContentRenderer { } let mut tera = Tera::new(&self.template_glob).into_diagnostic()?; super::processors::register_all(&mut tera); + let out_dir = self.ctx.dirs.output_dir.to_owned(); + let styles = Arc::clone(&self.styles); + let ctx = Arc::clone(&self.ctx); LoadDirContent - .chain( - RenderPage { - tera, - styles: self.styles.clone(), - ctx: self.ctx.clone(), + .construct(move |(files, default_template)| { + let step = RenderPage { + tera: tera.clone(), + styles: styles.clone(), + ctx: ctx.clone(), + default_template, } - .map(map_path_to_output(out_dir)) + .map(map_path_to_output(out_dir.clone())) .chain(SaveFile) - .parallel(), - ) + .parallel(); + + (files, step) + }) .parallel() .process(dirs) .await?; diff --git a/src/rendering/render_page.rs b/src/rendering/render_page.rs index 77cb9d9..78b1020 100644 --- a/src/rendering/render_page.rs +++ b/src/rendering/render_page.rs @@ -13,34 +13,32 @@ pub struct RenderPage { pub tera: Tera, pub styles: Arc>, pub ctx: Arc, + pub default_template: String, } #[async_trait] impl ProcessingStep for RenderPage { - type Input = (PathBuf, String); + type Input = PathBuf; type Output = (PathBuf, String); #[tracing::instrument(name = "render page", level = "trace", skip_all)] - async fn process(&self, (page_path, default_template): Self::Input) -> Result { + async fn process(&self, page_path: Self::Input) -> Result { let page = load_page(&page_path).await?; let mut context = TeraContext::new(); - let mut template_name = default_template; - let mut style_name = template_name.to_owned(); + let mut template_name = None; match page { crate::data::Page::Data(data) => { - if let Some(tmpl) = data.metadata.template { - template_name = tmpl.to_owned(); - style_name = tmpl; - } + template_name = data.metadata.template; context.insert("data", &data.data); } crate::data::Page::Content(content) => context.insert("content", &content), } + let template_name = template_name.as_ref().unwrap_or(&self.default_template); { let mut styles = self.styles.lock().await; let style_embed = styles - .get_style_embed(&style_name, &self.ctx.dirs.output_dir) + .get_style_embed(template_name, &self.ctx.dirs.output_dir) .await?; context.insert("style", &style_embed); };