Skip to main content

rsynko_media/
processing.rs

1use crate::ProcessingSorts;
2use alux_ext::ext;
3use ambassador::delegatable_trait;
4
5/// Provides the carriers and primitive constructors for processing programs.
6#[delegatable_trait]
7pub trait ProcessingProgramAlg: ProcessingSorts {
8    /// Defines a processor identity.
9    fn processor(&self, id: impl Into<String>) -> Self::Processor;
10    /// Defines application of one processor at one stage.
11    fn processing_step(&self, stage: ProcessingStage, processor: Self::Processor) -> Self::Step;
12    /// Defines the neutral processing program.
13    fn empty_processing(&self) -> Self::Program;
14    /// Defines a program from steps in declaration order.
15    fn processing(&self, steps: impl IntoIterator<Item = Self::Step>) -> Self::Program;
16    /// Defines sequential program composition.
17    fn then_processing(&self, first: Self::Program, next: Self::Program) -> Self::Program;
18}
19
20/// Specifies observation of a reified processing program.
21pub trait ProcessingProgramViewAlg: ProcessingSorts {
22    /// Observes steps in declaration order.
23    fn processing_steps<'a>(program: &'a Self::Program) -> impl Iterator<Item = &'a Self::Step>
24    where
25        Self::Step: 'a;
26    /// Observes the stage selecting one step.
27    fn processing_stage(step: &Self::Step) -> ProcessingStage;
28}
29
30/// Specifies application of primitive artifact-processing steps.
31pub trait ProcessingApplyAlg: ProcessingSorts {
32    /// Denotes a processor-specific failure.
33    type Error;
34
35    /// Applies one named artifact transformation.
36    ///
37    /// # Errors
38    ///
39    /// Returns the interpreter's error when the named transformation cannot be applied.
40    fn apply_processing_step(&mut self, step: &Self::Step) -> Result<(), Self::Error>;
41}
42
43/// Names the public processing stages in their product order.
44#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
45pub enum ProcessingStage {
46    /// Runs before entry filtering.
47    PreProcess,
48    /// Runs after entry filtering.
49    AfterFilter,
50    /// Runs on each video before downloading.
51    Video,
52    /// Runs immediately before downloading.
53    BeforeDownload,
54    /// Runs after downloading and before final movement.
55    PostProcess,
56    /// Runs after artifacts reach their final paths.
57    AfterMove,
58    /// Runs after all processing for one video.
59    AfterVideo,
60    /// Runs after all entries of one playlist.
61    Playlist,
62}
63
64/// Derives concise processing-program construction.
65#[ext(name = ProcessingProgramExt)]
66pub impl<This> This
67where
68    This: ProcessingProgramAlg,
69{
70    /// Defines one-step processing.
71    fn process_with(&self, stage: ProcessingStage, processor: impl Into<String>) -> This::Program {
72        let processor = self.processor(processor);
73        let step = self.processing_step(stage, processor);
74        self.processing([step])
75    }
76}
77
78/// Derives complete-program and single-stage processing from primitive step application.
79#[ext(name = ProcessingExt)]
80pub impl<This, Step, Program> This
81where
82    This: ProcessingApplyAlg<Step = Step> + ProcessingProgramViewAlg<Step = Step, Program = Program>,
83{
84    /// Interprets every step in declaration order.
85    ///
86    /// # Errors
87    ///
88    /// Returns the first step-application error and does not apply later steps.
89    fn run_processing_program(&mut self, program: &Program) -> Result<(), This::Error> {
90        This::processing_steps(program).try_for_each(|step| self.apply_processing_step(step))
91    }
92
93    /// Interprets one stage while preserving relative declaration order.
94    ///
95    /// # Errors
96    ///
97    /// Returns the first selected step-application error and does not apply later selected steps.
98    fn run_processing_stage(&mut self, program: &Program, stage: ProcessingStage) -> Result<(), This::Error> {
99        This::processing_steps(program)
100            .filter(|step| This::processing_stage(step) == stage)
101            .try_for_each(|step| self.apply_processing_step(step))
102    }
103}