Skip to main content

alpha2_eval/
error.rs

1use alpha2_media::SourceId;
2use alpha2_model::{
3    ClipBlendMode, ClipEffect, ClipId, CompositionId, ProjectId, TrackId, TrackKind,
4    VisualProperties,
5};
6use alpha2_time::TimeRange;
7use std::fmt;
8
9/// An evaluator failure.
10#[derive(Clone, Debug, PartialEq, Eq)]
11#[non_exhaustive]
12pub enum EvalError {
13    /// The input project violated a model invariant.
14    InvalidProject(alpha2_model::ModelError),
15    /// A valid range could not be represented during integer retiming.
16    UnmappableClip {
17        /// Clip whose source timestamp could not be calculated.
18        clip: ClipId,
19    },
20    /// A visible clip's composition cannot draw its output: it selects none,
21    /// a node the output needs has an unconnected input, a group input no
22    /// group node feeds is read, or a composition source reads a clip node
23    /// ([`crate::PlanError`]'s incomplete reasons), or the composition nests
24    /// or draws more than the planner holds.
25    IncompleteComposition {
26        /// The clip showing the composition.
27        clip: ClipId,
28        /// The composition.
29        composition: CompositionId,
30        /// What is missing.
31        reason: crate::PlanError,
32    },
33    /// The reusable index belongs to a different project.
34    IndexProjectMismatch {
35        /// Project identity captured when the index was built.
36        index_project: ProjectId,
37        /// Project identity passed to evaluation.
38        evaluated_project: ProjectId,
39    },
40}
41
42impl std::error::Error for EvalError {
43    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
44        match self {
45            Self::InvalidProject(error) => Some(error),
46            _ => None,
47        }
48    }
49}
50
51impl fmt::Display for EvalError {
52    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
53        match self {
54            Self::InvalidProject(error) => {
55                write!(formatter, "cannot index invalid project: {error}")
56            }
57            Self::UnmappableClip { clip } => {
58                write!(
59                    formatter,
60                    "clip {clip} cannot be mapped to a source timestamp"
61                )
62            }
63            Self::IncompleteComposition {
64                clip,
65                composition,
66                reason,
67            } => match reason {
68                crate::PlanError::NoOutput => write!(
69                    formatter,
70                    "composition {composition} of clip {clip} has no output"
71                ),
72                crate::PlanError::MissingInput { node, input } => write!(
73                    formatter,
74                    "input {input} of node {node} in composition {composition} of clip {clip} is not connected"
75                ),
76                crate::PlanError::UnboundGroupInput { node } => write!(
77                    formatter,
78                    "group input {node} in composition {composition} of clip {clip} is fed by no group node"
79                ),
80                crate::PlanError::ClipWithoutClip { node } => write!(
81                    formatter,
82                    "clip node {node} in composition {composition}, drawn as clip {clip}'s source, shows no clip"
83                ),
84                crate::PlanError::NestedTooDeep { node } => write!(
85                    formatter,
86                    "node {node} in composition {composition} of clip {clip} nests compositions more than {} deep",
87                    alpha2_model::MAX_COMPOSITION_DEPTH
88                ),
89                crate::PlanError::TooLarge => write!(
90                    formatter,
91                    "composition {composition} of clip {clip} draws more than {} nodes, or the project's compositions hold more than {} bytes once inlined",
92                    alpha2_model::MAX_INLINED_NODES,
93                    crate::MAX_PLAN_BYTES
94                ),
95            },
96            Self::IndexProjectMismatch {
97                index_project,
98                evaluated_project,
99            } => {
100                write!(
101                    formatter,
102                    "index belongs to project {index_project}, not {evaluated_project}"
103                )
104            }
105        }
106    }
107}
108
109#[derive(Clone, Debug)]
110pub(crate) struct IndexedClip {
111    pub(crate) clip_id: ClipId,
112    pub(crate) source_id: SourceId,
113    pub(crate) track_id: TrackId,
114    pub(crate) track_kind: TrackKind,
115    pub(crate) timeline_range: TimeRange,
116    pub(crate) source_range: TimeRange,
117    pub(crate) time_map: alpha2_model::TimeMap,
118    pub(crate) visual: VisualProperties,
119    pub(crate) composition: Option<crate::IndexedComposition>,
120    pub(crate) blend_mode: ClipBlendMode,
121    pub(crate) cache: alpha2_model::CacheIntent,
122    pub(crate) masks: Vec<alpha2_model::ShapeMask>,
123    pub(crate) matte: Option<alpha2_model::Matte>,
124    /// Whether another clip names this one as its matte.
125    pub(crate) is_matte: bool,
126    pub(crate) audio: alpha2_model::AudioProperties,
127    pub(crate) source_is_audible: bool,
128    pub(crate) generator: Option<alpha2_model::Generator>,
129    /// A shapes generator's tree, planned once per source.
130    pub(crate) shapes: Option<std::sync::Arc<crate::ShapesPlan>>,
131    /// For a composition source, its composition compiled to draw it.
132    pub(crate) source_composition: Option<(alpha2_model::CompositionId, crate::index::PlanSlot)>,
133    pub(crate) track_order: usize,
134    pub(crate) clip_order: usize,
135}
136
137#[derive(Clone, Debug)]
138pub(crate) struct IndexedTransition {
139    pub(crate) from_clip: ClipId,
140    pub(crate) to_clip: ClipId,
141    pub(crate) timeline_range: TimeRange,
142    pub(crate) easing: alpha2_model::Easing,
143    pub(crate) effect: ClipEffect,
144    pub(crate) track_order: usize,
145}
146
147#[derive(Clone, Debug)]
148pub(crate) struct IndexedCaptions {
149    pub(crate) track_id: TrackId,
150    pub(crate) track_order: usize,
151    pub(crate) captions: alpha2_model::Captions,
152}