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