1use crate::collection::{downcast_map, downcast_set};
2use crate::input::downcast_input;
3use crate::output_payload::{StoredOutput, boxed_output};
4use crate::{
5 CollectionNode, DependencyList, DeriveError, DerivedNode, Graph, InputNode, NodeId,
6 OutputError, OutputKey, Revision, ScopeId,
7};
8use core::marker::PhantomData;
9use std::collections::{BTreeMap, BTreeSet};
10use std::sync::Arc;
11
12type OutputFn<C> = dyn for<'ctx> Fn(&OutputContext<'ctx, C>) -> Result<Box<dyn StoredOutput>, OutputError>
13 + Send
14 + Sync;
15
16#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
18pub struct MaterializedOutput<O> {
19 key: OutputKey,
20 _marker: PhantomData<fn() -> O>,
21}
22
23impl<O> MaterializedOutput<O> {
24 pub(crate) fn new(key: OutputKey) -> Self {
25 Self {
26 key,
27 _marker: PhantomData,
28 }
29 }
30
31 pub fn key(&self) -> OutputKey {
33 self.key
34 }
35}
36
37#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
39pub struct OutputOptions {
40 pub emit_equal: bool,
42}
43
44#[derive(Clone, Debug, Eq, PartialEq)]
46pub struct OutputMeta {
47 key: OutputKey,
48 debug_name: String,
49 scope: ScopeId,
50 dependencies: DependencyList,
51 options: OutputOptions,
52 created_revision: Revision,
53}
54
55impl OutputMeta {
56 pub(crate) fn new(
57 key: OutputKey,
58 debug_name: impl Into<String>,
59 scope: ScopeId,
60 dependencies: DependencyList,
61 options: OutputOptions,
62 created_revision: Revision,
63 ) -> Self {
64 Self {
65 key,
66 debug_name: debug_name.into(),
67 scope,
68 dependencies,
69 options,
70 created_revision,
71 }
72 }
73
74 pub fn key(&self) -> OutputKey {
76 self.key
77 }
78
79 pub fn debug_name(&self) -> &str {
81 &self.debug_name
82 }
83
84 pub fn scope(&self) -> ScopeId {
86 self.scope
87 }
88
89 pub fn dependencies(&self) -> &DependencyList {
91 &self.dependencies
92 }
93
94 pub fn options(&self) -> OutputOptions {
96 self.options
97 }
98
99 pub fn created_revision(&self) -> Revision {
101 self.created_revision
102 }
103}
104
105pub(crate) struct OutputSpec<C> {
106 materialize: Arc<OutputFn<C>>,
107}
108
109impl<C> Clone for OutputSpec<C> {
110 fn clone(&self) -> Self {
111 Self {
112 materialize: Arc::clone(&self.materialize),
113 }
114 }
115}
116
117impl<C> OutputSpec<C> {
118 pub(crate) fn new<T>(
119 materialize: impl for<'ctx> Fn(&OutputContext<'ctx, C>) -> Result<T, OutputError>
120 + Send
121 + Sync
122 + 'static,
123 ) -> Self
124 where
125 T: Clone + PartialEq + Send + Sync + 'static,
126 {
127 Self {
128 materialize: Arc::new(move |ctx| materialize(ctx).map(boxed_output)),
129 }
130 }
131
132 pub(crate) fn materialize(
133 &self,
134 ctx: &OutputContext<'_, C>,
135 ) -> Result<Box<dyn StoredOutput>, OutputError> {
136 (self.materialize)(ctx)
137 }
138}
139
140pub struct OutputContext<'graph, C = ()> {
142 graph: &'graph Graph<C>,
143 declared_dependencies: &'graph [NodeId],
144}
145
146impl<'graph, C> OutputContext<'graph, C> {
147 pub(crate) fn new(graph: &'graph Graph<C>, declared_dependencies: &'graph [NodeId]) -> Self {
148 Self {
149 graph,
150 declared_dependencies,
151 }
152 }
153
154 pub fn input<T>(&self, input: InputNode<T>) -> Result<&'graph T, DeriveError>
156 where
157 T: Clone + PartialEq + Send + Sync + 'static,
158 {
159 let node = input.id();
160 self.require_declared(node)?;
161 self.graph
162 .input_values
163 .get(&node)
164 .and_then(|value| downcast_input::<T>(value.as_ref()))
165 .ok_or(DeriveError::MissingValue(node))
166 }
167
168 pub fn derived<T>(&self, derived: DerivedNode<T>) -> Result<&'graph T, DeriveError>
170 where
171 T: Clone + PartialEq + Send + Sync + 'static,
172 {
173 let node = derived.id();
174 self.require_declared(node)?;
175 self.graph
176 .derived_values
177 .get(&node)
178 .and_then(|value| downcast_input::<T>(value.as_ref()))
179 .ok_or(DeriveError::MissingValue(node))
180 }
181
182 pub fn map_collection<K, V>(
184 &self,
185 collection: CollectionNode<K, V>,
186 ) -> Result<&'graph BTreeMap<K, V>, DeriveError>
187 where
188 K: Clone + Ord + Send + Sync + 'static,
189 V: Clone + PartialEq + Send + Sync + 'static,
190 {
191 let node = collection.id();
192 self.require_declared(node)?;
193 self.graph
194 .validate_map_collection_read::<K, V>(node)
195 .map_err(|_| DeriveError::WrongCollectionType(node))?;
196 self.graph
197 .collection_values
198 .get(&node)
199 .and_then(|value| downcast_map::<K, V>(value.as_ref()))
200 .ok_or(DeriveError::MissingValue(node))
201 }
202
203 pub fn set_collection<K>(
205 &self,
206 collection: CollectionNode<K, ()>,
207 ) -> Result<&'graph BTreeSet<K>, DeriveError>
208 where
209 K: Clone + Ord + Send + Sync + 'static,
210 {
211 let node = collection.id();
212 self.require_declared(node)?;
213 self.graph
214 .validate_set_collection_read::<K>(node)
215 .map_err(|_| DeriveError::WrongCollectionType(node))?;
216 self.graph
217 .collection_values
218 .get(&node)
219 .and_then(|value| downcast_set::<K>(value.as_ref()))
220 .ok_or(DeriveError::MissingValue(node))
221 }
222
223 fn require_declared(&self, node: NodeId) -> Result<(), DeriveError> {
224 if self.declared_dependencies.contains(&node) {
225 Ok(())
226 } else {
227 Err(DeriveError::UndeclaredDependency(node))
228 }
229 }
230}