diff --git a/src/context.rs b/src/context.rs index 13d16bc..89268de 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,12 @@ use std::path::PathBuf; +#[derive(Clone, Debug)] pub struct Context { + pub dirs: Dirs, +} + +#[derive(Clone, Debug)] +pub struct Dirs { pub content_dir: PathBuf, pub template_dir: PathBuf, pub stylesheet_dir: PathBuf, diff --git a/src/main.rs b/src/main.rs index fb3a2cd..9020d18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::{path::Path, sync::Arc}; use args::BuildArgs; use clap::Parser; use config::{read_config, Config}; -use context::Context; +use context::{Context, Dirs}; use data::DirLoader; use miette::Result; use rendering::ContentRenderer; @@ -37,7 +37,7 @@ async fn build(args: &Args, _build_args: &BuildArgs, cfg: Config) -> Result<()> let base_path = &args.directory; let ctx = Arc::new(build_context(&base_path, &cfg)); - let dirs = DirLoader::new(ctx.content_dir.to_owned()) + let dirs = DirLoader::new(ctx.dirs.content_dir.to_owned()) .read_content() .await?; @@ -54,10 +54,12 @@ fn build_context(base_path: &Path, config: &Config) -> Context { let stylesheet_dir = base_path.join(folders.stylesheets.unwrap_or("styles".into())); Context { - content_dir, - template_dir, - stylesheet_dir, - output_dir, + dirs: Dirs { + content_dir, + template_dir, + stylesheet_dir, + output_dir, + }, } } diff --git a/src/pipeline.rs b/src/pipeline.rs index a4cef9e..46d4889 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -1,7 +1,14 @@ use async_trait::async_trait; +use futures::future; use miette::Result; +/// The result of combining two processing steps pub struct ProcessingChain>(S1, S2); + +/// An adapter to execute a step with multiple inputs in parallel +pub struct ParallelPipeline(S); + +/// A generic wrapper for processing pipelines pub struct ProcessingPipeline( Box>, ); @@ -27,6 +34,22 @@ impl> ProcessingStep } } +impl ParallelPipeline { + pub fn new(step: S) -> Self { + Self(step) + } +} + +#[async_trait] +impl ProcessingStep for ParallelPipeline { + type Input = Vec; + type Output = Vec; + + async fn process(&self, input: Self::Input) -> Result { + future::try_join_all(input.into_iter().map(|i| self.0.process(i))).await + } +} + pub trait ProcessingStepChain: Sized + ProcessingStep { fn chain>(self, other: S) -> ProcessingChain { ProcessingChain(self, other) diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index 9793b39..ddd80e6 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -23,8 +23,8 @@ pub struct ContentRenderer { impl ContentRenderer { pub async fn new(ctx: Arc) -> Result { - let template_glob = format!("{}/**/*", ctx.template_dir.to_string_lossy()); - let styles = load_stylesheets(&ctx.stylesheet_dir).await?; + let template_glob = format!("{}/**/*", ctx.dirs.template_dir.to_string_lossy()); + let styles = load_stylesheets(&ctx.dirs.stylesheet_dir).await?; Ok(Self { template_glob, @@ -35,8 +35,8 @@ impl ContentRenderer { #[tracing::instrument(level = "trace", skip_all)] pub async fn render_all(&self, dirs: Vec) -> Result<()> { - if self.ctx.output_dir.exists() { - fs::remove_dir_all(&self.ctx.output_dir) + if self.ctx.dirs.output_dir.exists() { + fs::remove_dir_all(&self.ctx.dirs.output_dir) .await .into_diagnostic()?; } @@ -99,7 +99,7 @@ impl ContentRenderer { { let mut styles = self.styles.lock().await; let style_embed = styles - .get_style_embed(&style_name, &self.ctx.output_dir) + .get_style_embed(&style_name, &self.ctx.dirs.output_dir) .await?; context.insert("style", &style_embed); }; @@ -110,9 +110,9 @@ impl ContentRenderer { .render(&format!("{template_name}.html"), &context) .into_diagnostic()?; let rel_path = page_path - .strip_prefix(&self.ctx.content_dir) + .strip_prefix(&self.ctx.dirs.content_dir) .into_diagnostic()?; - let mut out_path = self.ctx.output_dir.join(rel_path); + let mut out_path = self.ctx.dirs.output_dir.join(rel_path); out_path.set_extension("html"); let parent = out_path.parent().unwrap();