use crate::collection::{downcast_map, downcast_set};
use crate::input::downcast_input;
use crate::{
CollectionNode, DependencyList, DeriveError, DerivedNode, Graph, InputNode, NodeId,
OutputError, OutputKey, Revision, ScopeId, TransactionId,
};
use core::marker::PhantomData;
use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc;
type OutputFn<C, O> = dyn for<'ctx> Fn(&OutputContext<'ctx, C, O>) -> Result<O, OutputError>;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MaterializedOutput<O> {
key: OutputKey,
_marker: PhantomData<fn() -> O>,
}
impl<O> MaterializedOutput<O> {
pub(crate) fn new(key: OutputKey) -> Self {
Self {
key,
_marker: PhantomData,
}
}
pub fn key(&self) -> OutputKey {
self.key
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct OutputOptions {
pub emit_equal: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OutputMeta {
key: OutputKey,
debug_name: String,
scope: ScopeId,
dependencies: DependencyList,
options: OutputOptions,
created_revision: Revision,
}
impl OutputMeta {
pub(crate) fn new(
key: OutputKey,
debug_name: impl Into<String>,
scope: ScopeId,
dependencies: DependencyList,
options: OutputOptions,
created_revision: Revision,
) -> Self {
Self {
key,
debug_name: debug_name.into(),
scope,
dependencies,
options,
created_revision,
}
}
pub fn key(&self) -> OutputKey {
self.key
}
pub fn debug_name(&self) -> &str {
&self.debug_name
}
pub fn scope(&self) -> ScopeId {
self.scope
}
pub fn dependencies(&self) -> &DependencyList {
&self.dependencies
}
pub fn options(&self) -> OutputOptions {
self.options
}
pub fn created_revision(&self) -> Revision {
self.created_revision
}
}
pub(crate) struct OutputSpec<C, O> {
materialize: Arc<OutputFn<C, O>>,
}
impl<C, O> Clone for OutputSpec<C, O> {
fn clone(&self) -> Self {
Self {
materialize: Arc::clone(&self.materialize),
}
}
}
impl<C, O> OutputSpec<C, O> {
pub(crate) fn new(
materialize: impl for<'ctx> Fn(&OutputContext<'ctx, C, O>) -> Result<O, OutputError> + 'static,
) -> Self {
Self {
materialize: Arc::new(materialize),
}
}
pub(crate) fn materialize(&self, ctx: &OutputContext<'_, C, O>) -> Result<O, OutputError> {
(self.materialize)(ctx)
}
}
pub struct OutputContext<'graph, C = (), O = ()> {
graph: &'graph Graph<C, O>,
declared_dependencies: &'graph [NodeId],
}
impl<'graph, C, O> OutputContext<'graph, C, O> {
pub(crate) fn new(graph: &'graph Graph<C, O>, declared_dependencies: &'graph [NodeId]) -> Self {
Self {
graph,
declared_dependencies,
}
}
pub fn input<T>(&self, input: InputNode<T>) -> Result<&'graph T, DeriveError>
where
T: Clone + PartialEq + 'static,
{
let node = input.id();
self.require_declared(node)?;
self.graph
.input_values
.get(&node)
.and_then(|value| downcast_input::<T>(value.as_ref()))
.ok_or(DeriveError::MissingValue(node))
}
pub fn derived<T>(&self, derived: DerivedNode<T>) -> Result<&'graph T, DeriveError>
where
T: Clone + PartialEq + 'static,
{
let node = derived.id();
self.require_declared(node)?;
self.graph
.derived_values
.get(&node)
.and_then(|value| downcast_input::<T>(value.as_ref()))
.ok_or(DeriveError::MissingValue(node))
}
pub fn map_collection<K, V>(
&self,
collection: CollectionNode<K, V>,
) -> Result<&'graph BTreeMap<K, V>, DeriveError>
where
K: Clone + Ord + 'static,
V: Clone + PartialEq + 'static,
{
let node = collection.id();
self.require_declared(node)?;
self.graph
.validate_map_collection_read::<K, V>(node)
.map_err(|_| DeriveError::WrongCollectionType(node))?;
self.graph
.collection_values
.get(&node)
.and_then(|value| downcast_map::<K, V>(value.as_ref()))
.ok_or(DeriveError::MissingValue(node))
}
pub fn set_collection<K>(
&self,
collection: CollectionNode<K, ()>,
) -> Result<&'graph BTreeSet<K>, DeriveError>
where
K: Clone + Ord + 'static,
{
let node = collection.id();
self.require_declared(node)?;
self.graph
.validate_set_collection_read::<K>(node)
.map_err(|_| DeriveError::WrongCollectionType(node))?;
self.graph
.collection_values
.get(&node)
.and_then(|value| downcast_set::<K>(value.as_ref()))
.ok_or(DeriveError::MissingValue(node))
}
fn require_declared(&self, node: NodeId) -> Result<(), DeriveError> {
if self.declared_dependencies.contains(&node) {
Ok(())
} else {
Err(DeriveError::UndeclaredDependency(node))
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ClearReason {
ScopeClosed,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum RebaselineReason {
Requested,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OutputFrameKind<O> {
Baseline(O),
Delta(O),
Clear(ClearReason),
Rebaseline(O, RebaselineReason),
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OutputFrame<O> {
pub output_key: OutputKey,
pub scope: ScopeId,
pub transaction_id: TransactionId,
pub revision: Revision,
pub kind: OutputFrameKind<O>,
}