1use crate::collection::{downcast_map, downcast_set};
2use crate::input::downcast_input;
3use crate::{
4 CollectionNode, DependencyList, DeriveError, DerivedNode, Graph, InputNode, NodeId,
5 OutputError, OutputKey, Revision, ScopeId, TransactionId,
6};
7use core::marker::PhantomData;
8use std::collections::{BTreeMap, BTreeSet};
9use std::sync::Arc;
10
11type OutputFn<C, O> =
12 dyn for<'ctx> Fn(&OutputContext<'ctx, C, O>) -> Result<O, OutputError> + Send + Sync;
13
14#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
16pub struct MaterializedOutput<O> {
17 key: OutputKey,
18 _marker: PhantomData<fn() -> O>,
19}
20
21impl<O> MaterializedOutput<O> {
22 pub(crate) fn new(key: OutputKey) -> Self {
23 Self {
24 key,
25 _marker: PhantomData,
26 }
27 }
28
29 pub fn key(&self) -> OutputKey {
31 self.key
32 }
33}
34
35#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
37pub struct OutputOptions {
38 pub emit_equal: bool,
40}
41
42#[derive(Clone, Debug, Eq, PartialEq)]
44pub struct OutputMeta {
45 key: OutputKey,
46 debug_name: String,
47 scope: ScopeId,
48 dependencies: DependencyList,
49 options: OutputOptions,
50 created_revision: Revision,
51}
52
53impl OutputMeta {
54 pub(crate) fn new(
55 key: OutputKey,
56 debug_name: impl Into<String>,
57 scope: ScopeId,
58 dependencies: DependencyList,
59 options: OutputOptions,
60 created_revision: Revision,
61 ) -> Self {
62 Self {
63 key,
64 debug_name: debug_name.into(),
65 scope,
66 dependencies,
67 options,
68 created_revision,
69 }
70 }
71
72 pub fn key(&self) -> OutputKey {
74 self.key
75 }
76
77 pub fn debug_name(&self) -> &str {
79 &self.debug_name
80 }
81
82 pub fn scope(&self) -> ScopeId {
84 self.scope
85 }
86
87 pub fn dependencies(&self) -> &DependencyList {
89 &self.dependencies
90 }
91
92 pub fn options(&self) -> OutputOptions {
94 self.options
95 }
96
97 pub fn created_revision(&self) -> Revision {
99 self.created_revision
100 }
101}
102
103pub(crate) struct OutputSpec<C, O> {
104 materialize: Arc<OutputFn<C, O>>,
105}
106
107impl<C, O> Clone for OutputSpec<C, O> {
108 fn clone(&self) -> Self {
109 Self {
110 materialize: Arc::clone(&self.materialize),
111 }
112 }
113}
114
115impl<C, O> OutputSpec<C, O> {
116 pub(crate) fn new(
117 materialize: impl for<'ctx> Fn(&OutputContext<'ctx, C, O>) -> Result<O, OutputError>
118 + Send
119 + Sync
120 + 'static,
121 ) -> Self {
122 Self {
123 materialize: Arc::new(materialize),
124 }
125 }
126
127 pub(crate) fn materialize(&self, ctx: &OutputContext<'_, C, O>) -> Result<O, OutputError> {
128 (self.materialize)(ctx)
129 }
130}
131
132pub struct OutputContext<'graph, C = (), O = ()> {
134 graph: &'graph Graph<C, O>,
135 declared_dependencies: &'graph [NodeId],
136}
137
138impl<'graph, C, O> OutputContext<'graph, C, O> {
139 pub(crate) fn new(graph: &'graph Graph<C, O>, declared_dependencies: &'graph [NodeId]) -> Self {
140 Self {
141 graph,
142 declared_dependencies,
143 }
144 }
145
146 pub fn input<T>(&self, input: InputNode<T>) -> Result<&'graph T, DeriveError>
148 where
149 T: Clone + PartialEq + Send + Sync + 'static,
150 {
151 let node = input.id();
152 self.require_declared(node)?;
153 self.graph
154 .input_values
155 .get(&node)
156 .and_then(|value| downcast_input::<T>(value.as_ref()))
157 .ok_or(DeriveError::MissingValue(node))
158 }
159
160 pub fn derived<T>(&self, derived: DerivedNode<T>) -> Result<&'graph T, DeriveError>
162 where
163 T: Clone + PartialEq + Send + Sync + 'static,
164 {
165 let node = derived.id();
166 self.require_declared(node)?;
167 self.graph
168 .derived_values
169 .get(&node)
170 .and_then(|value| downcast_input::<T>(value.as_ref()))
171 .ok_or(DeriveError::MissingValue(node))
172 }
173
174 pub fn map_collection<K, V>(
176 &self,
177 collection: CollectionNode<K, V>,
178 ) -> Result<&'graph BTreeMap<K, V>, DeriveError>
179 where
180 K: Clone + Ord + Send + Sync + 'static,
181 V: Clone + PartialEq + Send + Sync + 'static,
182 {
183 let node = collection.id();
184 self.require_declared(node)?;
185 self.graph
186 .validate_map_collection_read::<K, V>(node)
187 .map_err(|_| DeriveError::WrongCollectionType(node))?;
188 self.graph
189 .collection_values
190 .get(&node)
191 .and_then(|value| downcast_map::<K, V>(value.as_ref()))
192 .ok_or(DeriveError::MissingValue(node))
193 }
194
195 pub fn set_collection<K>(
197 &self,
198 collection: CollectionNode<K, ()>,
199 ) -> Result<&'graph BTreeSet<K>, DeriveError>
200 where
201 K: Clone + Ord + Send + Sync + 'static,
202 {
203 let node = collection.id();
204 self.require_declared(node)?;
205 self.graph
206 .validate_set_collection_read::<K>(node)
207 .map_err(|_| DeriveError::WrongCollectionType(node))?;
208 self.graph
209 .collection_values
210 .get(&node)
211 .and_then(|value| downcast_set::<K>(value.as_ref()))
212 .ok_or(DeriveError::MissingValue(node))
213 }
214
215 fn require_declared(&self, node: NodeId) -> Result<(), DeriveError> {
216 if self.declared_dependencies.contains(&node) {
217 Ok(())
218 } else {
219 Err(DeriveError::UndeclaredDependency(node))
220 }
221 }
222}
223
224#[derive(Copy, Clone, Debug, Eq, PartialEq)]
226#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
227pub enum ClearReason {
228 ScopeClosed,
230}
231
232#[derive(Copy, Clone, Debug, Eq, PartialEq)]
234#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
235pub enum RebaselineReason {
236 Requested,
238}
239
240#[derive(Clone, Debug, Eq, PartialEq)]
242#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
243pub enum OutputFrameKind<O> {
244 Baseline(O),
246 Delta(O),
248 Clear(ClearReason),
250 Rebaseline(O, RebaselineReason),
252}
253
254#[derive(Clone, Debug, Eq, PartialEq)]
256#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
257pub struct OutputFrame<O> {
258 pub output_key: OutputKey,
260 pub scope: ScopeId,
262 pub transaction_id: TransactionId,
264 pub revision: Revision,
266 pub kind: OutputFrameKind<O>,
268}