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#[derive(Clone, Debug, PartialEq, Eq)]
11#[non_exhaustive]
12pub enum EvalError {
13 InvalidProject(alpha2_model::ModelError),
15 UnmappableClip {
17 clip: ClipId,
19 },
20 IncompleteComposition {
26 clip: ClipId,
28 composition: CompositionId,
30 reason: crate::PlanError,
32 },
33 IndexProjectMismatch {
35 index_project: ProjectId,
37 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 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 pub(crate) source_composition: Option<(alpha2_model::CompositionId, crate::index::PlanSlot)>,
131 pub(crate) track_order: usize,
132 pub(crate) clip_order: usize,
133}
134
135#[derive(Clone, Debug)]
136pub(crate) struct IndexedTransition {
137 pub(crate) from_clip: ClipId,
138 pub(crate) to_clip: ClipId,
139 pub(crate) timeline_range: TimeRange,
140 pub(crate) easing: alpha2_model::Easing,
141 pub(crate) effect: ClipEffect,
142 pub(crate) track_order: usize,
143}
144
145#[derive(Clone, Debug)]
146pub(crate) struct IndexedCaptions {
147 pub(crate) track_id: TrackId,
148 pub(crate) track_order: usize,
149 pub(crate) captions: alpha2_model::Captions,
150}