1use crate::{
2 AuditState, DependencyList, DerivedNode, GraphError, GraphResult, InputNode, NodeHandle,
3 NodeId, NodeKind, NodeMeta, OutputKey, OutputMeta, ResourceKey, Revision, ScopeId, ScopeMeta,
4 Transaction, TransactionId, TransactionOptions,
5 collection::{CollectionSpec, StoredCollection, StoredDiff},
6 derive::DerivedSpec,
7 input::{StoredInput, value_type},
8 output::OutputSpec,
9 output_payload::StoredOutput,
10 resource::ResourcePlanner,
11 topology::TopologyCache,
12};
13use std::collections::{BTreeMap, BTreeSet};
14
15pub struct Graph<C = ()> {
17 pub(crate) next_node_id: u64,
18 pub(crate) next_scope_id: u64,
19 pub(crate) next_output_key: u64,
20 pub(crate) next_transaction_id: TransactionId,
21 pub(crate) revision: Revision,
22 pub(crate) nodes: BTreeMap<NodeId, NodeMeta>,
23 pub(crate) scopes: BTreeMap<ScopeId, ScopeMeta>,
24 pub(crate) scope_children: BTreeMap<ScopeId, BTreeSet<ScopeId>>,
25 pub(crate) input_values: BTreeMap<NodeId, Box<dyn StoredInput>>,
26 pub(crate) derived_specs: BTreeMap<NodeId, DerivedSpec<C>>,
27 pub(crate) derived_values: BTreeMap<NodeId, Box<dyn StoredInput>>,
28 pub(crate) collection_specs: BTreeMap<NodeId, CollectionSpec<C>>,
29 pub(crate) collection_values: BTreeMap<NodeId, Box<dyn StoredCollection>>,
30 pub(crate) previous_collection_values: BTreeMap<NodeId, Box<dyn StoredCollection>>,
31 pub(crate) collection_diffs: BTreeMap<NodeId, Box<dyn StoredDiff>>,
32 pub(crate) resource_planners: Vec<ResourcePlanner<C>>,
33 pub(crate) resource_owners: BTreeMap<ResourceKey, BTreeSet<ScopeId>>,
34 pub(crate) resource_payloads: BTreeMap<ResourceKey, C>,
35 pub(crate) resource_acquisitions: BTreeMap<(ScopeId, ResourceKey), u64>,
36 pub(crate) next_resource_acquisition: u64,
37 pub(crate) output_specs: BTreeMap<OutputKey, OutputSpec<C>>,
38 pub(crate) output_values: BTreeMap<OutputKey, Box<dyn StoredOutput>>,
39 pub(crate) outputs: BTreeMap<OutputKey, OutputMeta>,
40 pub(crate) topology_cache: TopologyCache,
41 pub(crate) audit: AuditState,
42 pub(crate) transaction_open: bool,
43}
44
45impl<C> Graph<C> {
46 pub fn new_with_command_type() -> Self {
48 Self {
49 next_node_id: 1,
50 next_scope_id: 1,
51 next_output_key: 1,
52 next_transaction_id: TransactionId::default(),
53 revision: Revision::default(),
54 nodes: BTreeMap::new(),
55 scopes: BTreeMap::new(),
56 scope_children: BTreeMap::new(),
57 input_values: BTreeMap::new(),
58 derived_specs: BTreeMap::new(),
59 derived_values: BTreeMap::new(),
60 collection_specs: BTreeMap::new(),
61 collection_values: BTreeMap::new(),
62 previous_collection_values: BTreeMap::new(),
63 collection_diffs: BTreeMap::new(),
64 resource_planners: Vec::new(),
65 resource_owners: BTreeMap::new(),
66 resource_payloads: BTreeMap::new(),
67 resource_acquisitions: BTreeMap::new(),
68 next_resource_acquisition: 1,
69 output_specs: BTreeMap::new(),
70 output_values: BTreeMap::new(),
71 outputs: BTreeMap::new(),
72 topology_cache: TopologyCache::default(),
73 audit: AuditState::default(),
74 transaction_open: false,
75 }
76 }
77
78 pub fn revision(&self) -> Revision {
80 self.revision
81 }
82
83 pub fn begin_transaction(&mut self) -> GraphResult<Transaction<'_, C>>
85 where
86 C: Clone,
87 {
88 self.begin_transaction_with_options(TransactionOptions::default())
89 }
90
91 pub fn begin_transaction_with_options(
93 &mut self,
94 options: TransactionOptions,
95 ) -> GraphResult<Transaction<'_, C>>
96 where
97 C: Clone,
98 {
99 if self.transaction_open {
100 return Err(GraphError::NestedTransaction);
101 }
102
103 self.transaction_open = true;
104 let id = self.allocate_transaction_id();
105 Ok(Transaction::new(self, id, options))
106 }
107
108 pub(crate) fn create_scope_with_parent_direct(
109 &mut self,
110 id: ScopeId,
111 debug_name: impl Into<String>,
112 parent: Option<ScopeId>,
113 ) -> GraphResult<ScopeId> {
114 if let Some(parent) = parent {
115 let parent_meta = self.require_scope(parent)?;
116 if parent_meta.is_closed() {
117 return Err(GraphError::ScopeAlreadyClosed(parent));
118 }
119 }
120
121 self.scopes
122 .insert(id, ScopeMeta::new(id, debug_name, parent));
123 if let Some(parent) = parent {
124 self.scope_children.entry(parent).or_default().insert(id);
125 }
126 Ok(id)
127 }
128
129 pub(crate) fn input_direct<T>(
130 &mut self,
131 id: NodeId,
132 debug_name: impl Into<String>,
133 ) -> GraphResult<InputNode<T>>
134 where
135 T: Clone + PartialEq + Send + Sync + 'static,
136 {
137 let meta = NodeMeta::new(
138 id,
139 NodeKind::Input,
140 debug_name,
141 DependencyList::empty(),
142 self.revision,
143 Some(value_type::<T>()),
144 );
145 self.invalidate_topology_cache();
146 self.nodes.insert(id, meta);
147 Ok(InputNode::new(id))
148 }
149
150 pub(crate) fn derived_direct<T>(
151 &mut self,
152 id: NodeId,
153 debug_name: impl Into<String>,
154 dependencies: DependencyList,
155 derive: impl for<'ctx> Fn(&crate::DeriveContext<'ctx, C>) -> Result<T, crate::DeriveError>
156 + Send
157 + Sync
158 + 'static,
159 ) -> GraphResult<DerivedNode<T>>
160 where
161 T: Clone + PartialEq + Send + Sync + 'static,
162 {
163 self.validate_dependencies(id, &dependencies)?;
164 self.reject_collection_dependencies(&dependencies)?;
165 let meta = NodeMeta::new(
166 id,
167 NodeKind::Derived,
168 debug_name,
169 dependencies,
170 self.revision,
171 Some(value_type::<T>()),
172 );
173 self.invalidate_topology_cache();
174 self.nodes.insert(id, meta);
175 self.derived_specs.insert(id, DerivedSpec::<C>::new(derive));
176 Ok(DerivedNode::new(id))
177 }
178
179 pub(crate) fn attach_node_to_scope_direct(
180 &mut self,
181 node_id: NodeId,
182 scope: ScopeId,
183 ) -> GraphResult<()> {
184 let scope_meta = self.require_scope(scope)?;
185 if scope_meta.is_closed() {
186 return Err(GraphError::ScopeAlreadyClosed(scope));
187 }
188
189 let node_meta = self
190 .nodes
191 .get_mut(&node_id)
192 .ok_or(GraphError::UnknownNode(node_id))?;
193
194 if node_meta.owning_scope().is_some() {
195 return Err(GraphError::NodeAlreadyAttached(node_id));
196 }
197
198 node_meta.attach_scope(scope);
199 Ok(())
200 }
201
202 pub fn node_meta<H: NodeHandle>(&self, node: H) -> Option<&NodeMeta> {
204 self.nodes.get(&node.id())
205 }
206
207 pub fn node_meta_by_id(&self, id: NodeId) -> Option<&NodeMeta> {
209 self.nodes.get(&id)
210 }
211
212 pub fn scope_meta(&self, id: ScopeId) -> Option<&ScopeMeta> {
214 self.scopes.get(&id)
215 }
216
217 pub fn output_meta(&self, key: OutputKey) -> Option<&OutputMeta> {
219 self.outputs.get(&key)
220 }
221
222 pub fn dependencies<H: NodeHandle>(&self, node: H) -> Option<&DependencyList> {
224 self.node_meta(node).map(NodeMeta::dependencies)
225 }
226
227 pub fn nodes(&self) -> impl Iterator<Item = &NodeMeta> {
229 self.nodes.values()
230 }
231
232 pub fn scopes(&self) -> impl Iterator<Item = &ScopeMeta> {
234 self.scopes.values()
235 }
236
237 pub(crate) fn allocate_node_id(&mut self) -> NodeId {
238 let id = NodeId::from_index(self.next_node_id);
239 self.next_node_id += 1;
240 id
241 }
242
243 pub(crate) fn allocate_scope_id(&mut self) -> ScopeId {
244 let id = ScopeId::from_index(self.next_scope_id);
245 self.next_scope_id += 1;
246 id
247 }
248
249 pub(crate) fn allocate_output_key(&mut self) -> OutputKey {
250 let key = OutputKey::from_index(self.next_output_key);
251 self.next_output_key += 1;
252 key
253 }
254
255 fn allocate_transaction_id(&mut self) -> TransactionId {
256 self.next_transaction_id = self.next_transaction_id.next();
257 self.next_transaction_id
258 }
259
260 pub(crate) fn require_scope(&self, id: ScopeId) -> GraphResult<&ScopeMeta> {
261 self.scopes.get(&id).ok_or(GraphError::UnknownScope(id))
262 }
263}