Avoid cloning so much for DynamicNodeFactory keys

This commit is contained in:
Shadowfacts 2025-02-19 00:50:17 -05:00
parent 175d429240
commit 50060a5f9d
4 changed files with 84 additions and 78 deletions

View File

@ -253,10 +253,10 @@ fn find_excerpt(post: &Post<HtmlContent>) -> Option<String> {
struct MakeWritePosts { struct MakeWritePosts {
posts: DynamicInput<Option<Post<HtmlContent>>>, posts: DynamicInput<Option<Post<HtmlContent>>>,
article_template: Input<Templates>, article_template: Input<Templates>,
permalink_factory: DynamicNodeFactory<PathBuf, String>, permalink_factory: DynamicNodeFactory<NodeId, String>,
output_path_factory: DynamicNodeFactory<PathBuf, PathBuf>, output_path_factory: DynamicNodeFactory<NodeId, PathBuf>,
build_context_factory: DynamicNodeFactory<PathBuf, Context>, build_context_factory: DynamicNodeFactory<NodeId, Context>,
render_factory: DynamicNodeFactory<PathBuf, String>, render_factory: DynamicNodeFactory<NodeId, String>,
} }
impl MakeWritePosts { impl MakeWritePosts {
fn new(posts: DynamicInput<Option<Post<HtmlContent>>>, templates: Input<Templates>) -> Self { fn new(posts: DynamicInput<Option<Post<HtmlContent>>>, templates: Input<Templates>) -> Self {
@ -274,47 +274,48 @@ impl DynamicRule for MakeWritePosts {
type ChildOutput = String; type ChildOutput = String;
fn evaluate(&mut self, ctx: &mut impl DynamicRuleContext) -> Vec<Input<Self::ChildOutput>> { fn evaluate(&mut self, ctx: &mut impl DynamicRuleContext) -> Vec<Input<Self::ChildOutput>> {
for post_input in self.posts.value().inputs.iter() { for post_input in self.posts.value().inputs.iter() {
if let Some(post) = post_input.value().as_ref() { if post_input.value().is_some() {
let permalink = self let permalink = self
.permalink_factory .permalink_factory
.add_node(ctx, post.path.clone(), |ctx| { .add_node(ctx, post_input.node_id(), |ctx| {
ctx.add_rule(PostPermalink(post_input.clone())) ctx.add_rule(PostPermalink(post_input.clone()))
}); });
let context = self let context =
.build_context_factory self.build_context_factory
.add_node(ctx, post.path.clone(), |ctx| { .add_node(ctx, post_input.node_id(), |ctx| {
ctx.add_rule(BuildTemplateContext::new( ctx.add_rule(BuildTemplateContext::new(
permalink.clone().into(), permalink.clone().into(),
post_input.clone(), post_input.clone(),
|post_opt, ctx| { |post_opt, ctx| {
let post = post_opt.as_ref().unwrap(); let post = post_opt.as_ref().unwrap();
ctx.insert("metadata", &post.metadata); ctx.insert("metadata", &post.metadata);
ctx.insert( ctx.insert(
"word_count", "word_count",
&post &post
.word_count .word_count
.expect("post should have word count when rendering"), .expect("post should have word count when rendering"),
); );
ctx.insert("content", post.content.html()); ctx.insert("content", post.content.html());
}, },
)) ))
}); });
let output_path = let output_path =
self.output_path_factory self.output_path_factory
.add_node(ctx, post.path.clone(), |ctx| { .add_node(ctx, post_input.node_id(), |ctx| {
ctx.add_rule(PostOutputPath(permalink)) ctx.add_rule(PostOutputPath(permalink))
}); });
self.render_factory.add_node(ctx, post.path.clone(), |ctx| { self.render_factory
ctx.add_rule(RenderTemplate { .add_node(ctx, post_input.node_id(), |ctx| {
name: "article", ctx.add_rule(RenderTemplate {
output_path: output_path.into(), name: "article",
templates: self.article_template.clone(), output_path: output_path.into(),
context: context.into(), templates: self.article_template.clone(),
}) context: context.into(),
}); })
});
} }
} }
self.permalink_factory.finalize_nodes(ctx); self.permalink_factory.finalize_nodes(ctx);

View File

@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use compute_graph::{ use compute_graph::{
NodeId,
builder::GraphBuilder, builder::GraphBuilder,
input::{DynamicInput, Input, InputVisitable}, input::{DynamicInput, Input, InputVisitable},
rule::{DynamicNodeFactory, DynamicRule, Rule}, rule::{DynamicNodeFactory, DynamicRule, Rule},
@ -167,8 +168,8 @@ struct MakeWriteTagPages {
tags: DynamicInput<TagAndPosts>, tags: DynamicInput<TagAndPosts>,
#[skip_visit] #[skip_visit]
templates: Input<Templates>, templates: Input<Templates>,
build_context_factory: DynamicNodeFactory<String, Context>, build_context_factory: DynamicNodeFactory<NodeId, Context>,
render_factory: DynamicNodeFactory<String, String>, render_factory: DynamicNodeFactory<NodeId, String>,
} }
impl MakeWriteTagPages { impl MakeWriteTagPages {
fn new(tags: DynamicInput<TagAndPosts>, templates: Input<Templates>) -> Self { fn new(tags: DynamicInput<TagAndPosts>, templates: Input<Templates>) -> Self {
@ -189,27 +190,28 @@ impl DynamicRule for MakeWriteTagPages {
for tag_input in self.tags.value().inputs.iter() { for tag_input in self.tags.value().inputs.iter() {
let tag_and_posts = tag_input.value(); let tag_and_posts = tag_input.value();
let slug = &tag_and_posts.tag.slug; let slug = &tag_and_posts.tag.slug;
let template_context = self let template_context =
.build_context_factory self.build_context_factory
.add_node(ctx, slug.clone(), |ctx| { .add_node(ctx, tag_input.node_id(), |ctx| {
ctx.add_rule(BuildTemplateContext::new( ctx.add_rule(BuildTemplateContext::new(
format!("/{slug}/").into(), format!("/{slug}/").into(),
tag_input.clone(), tag_input.clone(),
|tag_and_posts, ctx| { |tag_and_posts, ctx| {
ctx.insert("tag_name", &tag_and_posts.tag.name); ctx.insert("tag_name", &tag_and_posts.tag.name);
ctx.insert("years", &tag_and_posts.posts.years()); ctx.insert("years", &tag_and_posts.posts.years());
ctx.insert("posts_by_year", &tag_and_posts.posts.0); ctx.insert("posts_by_year", &tag_and_posts.posts.0);
}, },
)) ))
});
self.render_factory
.add_node(ctx, tag_input.node_id(), |ctx| {
ctx.add_rule(RenderTemplate {
name: "tag",
output_path: format!("/{slug}/index.html").into(),
templates: self.templates.clone(),
context: template_context.into(),
})
}); });
self.render_factory.add_node(ctx, slug.clone(), |ctx| {
ctx.add_rule(RenderTemplate {
name: "tag",
output_path: format!("/{slug}/index.html").into(),
templates: self.templates.clone(),
context: template_context.into(),
})
});
} }
self.build_context_factory.finalize_nodes(ctx); self.build_context_factory.finalize_nodes(ctx);
self.render_factory.all_nodes(ctx) self.render_factory.all_nodes(ctx)

View File

@ -14,6 +14,7 @@ use super::util::slugify::slugify;
use super::util::{content_path, from_frontmatter}; use super::util::{content_path, from_frontmatter};
use super::{FileWatcher, templates::Templates}; use super::{FileWatcher, templates::Templates};
// tutorials are not actively maintained, so reading/parsing posts doesn't use the graph or watcher
pub fn make_graph( pub fn make_graph(
builder: &mut GraphBuilder<(), Asynchronous>, builder: &mut GraphBuilder<(), Asynchronous>,
default_template: Input<Templates>, default_template: Input<Templates>,

View File

@ -7,6 +7,7 @@ use std::{
use anyhow::anyhow; use anyhow::anyhow;
use chrono::{DateTime, Local, NaiveDate}; use chrono::{DateTime, Local, NaiveDate};
use compute_graph::{ use compute_graph::{
NodeId,
builder::GraphBuilder, builder::GraphBuilder,
input::{DynamicInput, Input, InputVisitable}, input::{DynamicInput, Input, InputVisitable},
rule::{DynamicNodeFactory, DynamicRule, DynamicRuleContext, Rule}, rule::{DynamicNodeFactory, DynamicRule, DynamicRuleContext, Rule},
@ -266,8 +267,8 @@ struct MakeRenderShows {
shows: DynamicInput<Option<Show>>, shows: DynamicInput<Option<Show>>,
#[skip_visit] #[skip_visit]
templates: Input<Templates>, templates: Input<Templates>,
build_context_factory: DynamicNodeFactory<String, Context>, build_context_factory: DynamicNodeFactory<NodeId, Context>,
render_factory: DynamicNodeFactory<String, String>, render_factory: DynamicNodeFactory<NodeId, String>,
} }
impl MakeRenderShows { impl MakeRenderShows {
fn new(shows: DynamicInput<Option<Show>>, templates: Input<Templates>) -> Self { fn new(shows: DynamicInput<Option<Show>>, templates: Input<Templates>) -> Self {
@ -284,27 +285,28 @@ impl DynamicRule for MakeRenderShows {
fn evaluate(&mut self, ctx: &mut impl DynamicRuleContext) -> Vec<Input<Self::ChildOutput>> { fn evaluate(&mut self, ctx: &mut impl DynamicRuleContext) -> Vec<Input<Self::ChildOutput>> {
for show_input in self.shows.value().inputs.iter() { for show_input in self.shows.value().inputs.iter() {
if let Some(show) = show_input.value().as_ref() { if let Some(show) = show_input.value().as_ref() {
let context = self let context =
.build_context_factory self.build_context_factory
.add_node(ctx, show.slug.clone(), |ctx| { .add_node(ctx, show_input.node_id(), |ctx| {
ctx.add_rule(BuildTemplateContext::new( ctx.add_rule(BuildTemplateContext::new(
format!("/tv/{}/", show.slug).into(), format!("/tv/{}/", show.slug).into(),
show_input.clone(), show_input.clone(),
|show, context| { |show, context| {
if let Some(show) = show { if let Some(show) = show {
context.insert("show", show); context.insert("show", show);
} }
}, },
)) ))
});
self.render_factory
.add_node(ctx, show_input.node_id(), |ctx| {
ctx.add_rule(RenderTemplate {
name: "show",
output_path: format!("/tv/{}/index.html", show.slug).into(),
templates: self.templates.clone(),
context: context.into(),
})
}); });
self.render_factory.add_node(ctx, show.slug.clone(), |ctx| {
ctx.add_rule(RenderTemplate {
name: "show",
output_path: format!("/tv/{}/index.html", show.slug).into(),
templates: self.templates.clone(),
context: context.into(),
})
});
} }
} }
self.build_context_factory.finalize_nodes(ctx); self.build_context_factory.finalize_nodes(ctx);