Skip to main content

trellis_core/
output_frame.rs

1use crate::output_payload::{OutputPayload, StoredOutput};
2use crate::{MaterializedOutput, OutputKey, Revision, ScopeId, TransactionId};
3
4/// Reason a materialized output was cleared.
5#[derive(Copy, Clone, Debug, Eq, PartialEq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub enum ClearReason {
8    /// The owning scope was closed.
9    ScopeClosed,
10}
11
12/// Reason a materialized output was rebaselined.
13#[derive(Copy, Clone, Debug, Eq, PartialEq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub enum RebaselineReason {
16    /// The host explicitly requested a rebaseline.
17    Requested,
18}
19
20/// Data-only output frame kind.
21#[derive(Clone, Debug, PartialEq)]
22pub enum OutputFrameKind {
23    /// Complete current state for a newly attached output.
24    Baseline(OutputPayload),
25    /// State-replacement delta for an existing output.
26    Delta(OutputPayload),
27    /// Clear the consumer state for this output.
28    Clear(ClearReason),
29    /// Complete current state after an explicit discontinuity.
30    Rebaseline(OutputPayload, RebaselineReason),
31}
32
33impl OutputFrameKind {
34    /// Builds a baseline frame kind with a typed payload.
35    pub fn baseline<T>(value: T) -> Self
36    where
37        T: Clone + PartialEq + Send + Sync + 'static,
38    {
39        Self::Baseline(OutputPayload::new(value))
40    }
41
42    /// Builds a delta frame kind with a typed payload.
43    pub fn delta<T>(value: T) -> Self
44    where
45        T: Clone + PartialEq + Send + Sync + 'static,
46    {
47        Self::Delta(OutputPayload::new(value))
48    }
49
50    /// Builds a rebaseline frame kind with a typed payload.
51    pub fn rebaseline<T>(value: T, reason: RebaselineReason) -> Self
52    where
53        T: Clone + PartialEq + Send + Sync + 'static,
54    {
55        Self::Rebaseline(OutputPayload::new(value), reason)
56    }
57
58    pub(crate) fn baseline_from_stored(value: Box<dyn StoredOutput>) -> Self {
59        Self::Baseline(OutputPayload::from_stored(value))
60    }
61
62    pub(crate) fn delta_from_stored(value: Box<dyn StoredOutput>) -> Self {
63        Self::Delta(OutputPayload::from_stored(value))
64    }
65
66    pub(crate) fn rebaseline_from_stored(
67        value: Box<dyn StoredOutput>,
68        reason: RebaselineReason,
69    ) -> Self {
70        Self::Rebaseline(OutputPayload::from_stored(value), reason)
71    }
72
73    /// Returns this frame payload as the requested type, if this is a payload frame.
74    pub fn payload<T>(&self) -> Option<&T>
75    where
76        T: Clone + PartialEq + Send + Sync + 'static,
77    {
78        match self {
79            Self::Baseline(payload) | Self::Delta(payload) | Self::Rebaseline(payload, _) => {
80                payload.get::<T>()
81            }
82            Self::Clear(_) => None,
83        }
84    }
85
86    /// Returns the clear reason, if this is a clear frame.
87    pub fn clear_reason(&self) -> Option<ClearReason> {
88        match self {
89            Self::Clear(reason) => Some(*reason),
90            _ => None,
91        }
92    }
93
94    /// Returns the rebaseline reason, if this is a rebaseline frame.
95    pub fn rebaseline_reason(&self) -> Option<RebaselineReason> {
96        match self {
97            Self::Rebaseline(_, reason) => Some(*reason),
98            _ => None,
99        }
100    }
101}
102
103/// Data-only materialized output frame returned from a transaction.
104#[derive(Clone, Debug, PartialEq)]
105pub struct OutputFrame {
106    /// Output key this frame targets.
107    pub output_key: OutputKey,
108    /// Scope that owns this output.
109    pub scope: ScopeId,
110    /// Transaction that emitted this frame.
111    pub transaction_id: TransactionId,
112    /// Graph revision this frame belongs to.
113    pub revision: Revision,
114    /// Frame payload.
115    pub kind: OutputFrameKind,
116}
117
118impl OutputFrame {
119    /// Returns this frame payload as the requested type when both key and type match.
120    pub fn payload_for<T>(&self, output: &MaterializedOutput<T>) -> Option<&T>
121    where
122        T: Clone + PartialEq + Send + Sync + 'static,
123    {
124        (self.output_key == output.key())
125            .then(|| self.kind.payload::<T>())
126            .flatten()
127    }
128}