Skip to main content

trellis_core/
resource_build.rs

1use crate::{
2    CollectionNode, GraphError, GraphResult, MapDiff, PlanContext, PlanError, ResourceKey,
3    ResourcePlan, SetDiff, Transaction, resource::ResourcePlanner,
4};
5
6impl<C: 'static> Transaction<'_, C> {
7    /// Stages a map-diff resource planner.
8    pub fn map_resource_planner<K, V>(
9        &mut self,
10        collection: CollectionNode<K, V>,
11        scope: crate::ScopeId,
12        planner: impl for<'ctx> Fn(
13            &PlanContext<'ctx, MapDiff<K, V>>,
14        ) -> Result<ResourcePlan<C>, PlanError>
15        + Send
16        + Sync
17        + 'static,
18    ) -> GraphResult<()>
19    where
20        K: Clone + Ord + Send + Sync + 'static,
21        V: Clone + PartialEq + Send + Sync + 'static,
22    {
23        self.ensure_open()?;
24        self.working.require_scope_open(scope)?;
25        self.working
26            .validate_map_collection_read::<K, V>(collection.id())?;
27        let resource_planner = ResourcePlanner::new(collection.id(), scope, move |graph| {
28            let Some(diff) = graph.map_diff(collection)? else {
29                return Ok(ResourcePlan::new());
30            };
31            let ctx = PlanContext::new(scope, diff);
32            planner(&ctx).map_err(|error| GraphError::PlanFailed(scope, error))
33        });
34        self.staged_resource_planner_collections
35            .push(collection.id());
36        self.working.resource_planners.push(resource_planner);
37        self.graph_mutated = true;
38        Ok(())
39    }
40
41    /// Stages a set-diff resource planner.
42    pub fn set_resource_planner<K>(
43        &mut self,
44        collection: CollectionNode<K, ()>,
45        scope: crate::ScopeId,
46        planner: impl for<'ctx> Fn(&PlanContext<'ctx, SetDiff<K>>) -> Result<ResourcePlan<C>, PlanError>
47        + Send
48        + Sync
49        + 'static,
50    ) -> GraphResult<()>
51    where
52        K: Clone + Ord + Send + Sync + 'static,
53    {
54        self.ensure_open()?;
55        self.working.require_scope_open(scope)?;
56        self.working
57            .validate_set_collection_read::<K>(collection.id())?;
58        let resource_planner = ResourcePlanner::new(collection.id(), scope, move |graph| {
59            let Some(diff) = graph.set_diff(collection)? else {
60                return Ok(ResourcePlan::new());
61            };
62            let ctx = PlanContext::new(scope, diff);
63            planner(&ctx).map_err(|error| GraphError::PlanFailed(scope, error))
64        });
65        self.staged_resource_planner_collections
66            .push(collection.id());
67        self.working.resource_planners.push(resource_planner);
68        self.graph_mutated = true;
69        Ok(())
70    }
71
72    /// Stages a set-diff planner that opens added members and closes removed members.
73    pub fn open_close_planner<K>(
74        &mut self,
75        collection: CollectionNode<K, ()>,
76        scope: crate::ScopeId,
77        key: impl Fn(&K) -> ResourceKey + Send + Sync + 'static,
78        open: impl Fn(&K) -> C + Send + Sync + 'static,
79    ) -> GraphResult<()>
80    where
81        K: Clone + Ord + Send + Sync + 'static,
82    {
83        self.set_resource_planner(collection, scope, move |ctx| {
84            let mut plan = ResourcePlan::new();
85            for added in &ctx.diff().added {
86                plan.open(key(&added.value), ctx.scope(), open(&added.value));
87            }
88            for removed in &ctx.diff().removed {
89                plan.close(key(&removed.value), ctx.scope());
90            }
91            Ok(plan)
92        })
93    }
94}