Add construct method for conditionial renderers

feature/processing-pipeline
trivernis 1 year ago
parent a2eeb4fe73
commit 6178a045e7
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -11,6 +11,12 @@ pub struct Parallel<S: ProcessingStep>(S);
/// An adapter to map the result of the pipeline
pub struct Map<S: ProcessingStep, T: Send + Sync>(S, Box<dyn Fn(S::Output) -> T + Send + Sync>);
/// An adapter to dynamically construct the next step mapper depending on the previous one
pub struct Construct<S1: ProcessingStep, S2: ProcessingStep<Input = T>, T>(
S1,
Box<dyn Fn(S1::Output) -> (T, S2) + Send + Sync>,
);
/// A generic wrapper for processing pipelines
pub struct ProcessingPipeline<I: Send + Sync, O: Send + Sync>(
Box<dyn ProcessingStep<Input = I, Output = O>>,
@ -87,10 +93,41 @@ impl<S: ProcessingStep, T: Send + Sync> ProcessingStep for Map<S, T> {
async fn process(&self, input: Self::Input) -> Result<Self::Output> {
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<Input = T>,
T: Send + Sync,
>(
self,
construct_fn: F,
) -> Construct<Self, S, T> {
Construct(self, Box::new(construct_fn))
}
}
impl<S: ProcessingStep> ProcessingConstruct for S {}
#[async_trait]
impl<S1: ProcessingStep, S2: ProcessingStep<Input = T>, T: Send + Sync> ProcessingStep
for Construct<S1, S2, T>
{
type Input = S1::Input;
type Output = S2::Output;
async fn process(&self, input: Self::Input) -> Result<Self::Output> {
let inner_output = self.0.process(input).await?;
let (new_input, step) = self.1(inner_output);
step.process(new_input).await
}
}
#[async_trait]
impl<I: Send + Sync, O: Send + Sync> ProcessingStep for ProcessingPipeline<I, O> {
type Input = I;

@ -10,7 +10,7 @@ pub struct LoadDirContent;
#[async_trait]
impl ProcessingStep for LoadDirContent {
type Input = FolderData;
type Output = Vec<(PathBuf, String)>;
type Output = (Vec<PathBuf>, String);
#[tracing::instrument(name = "load dir", level = "trace", skip_all)]
async fn process(&self, input: Self::Input) -> Result<Self::Output> {
@ -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))
}
}

@ -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?;

@ -13,34 +13,32 @@ pub struct RenderPage {
pub tera: Tera,
pub styles: Arc<Mutex<Stylesheets>>,
pub ctx: Arc<Context>,
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<Self::Output> {
async fn process(&self, page_path: Self::Input) -> Result<Self::Output> {
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);
};

Loading…
Cancel
Save