Skip to main content

rsynko_manager/
options.rs

1use alux_ext::ext;
2use alux_sdk::trait_algebra;
3use rsynko_media::{FormatPredicateAlg, FormatPredicateExt, FormatSelectionAlg};
4
5/// Specifies what one request states about the media it selects.
6pub trait RequestOptionsAlg {
7    /// Observes what performs the request.
8    fn performer(&self) -> Performer;
9
10    /// Observes the stream roles the request prefers, and that it chooses no media when it
11    /// transfers something a media role says nothing about.
12    fn media_streams(&self) -> Option<MediaStreams>;
13
14    /// Observes the one choice the request fixes, when it fixes one.
15    ///
16    /// What the choices are depends on what the request transfers: one representation of a media
17    /// item, or one way of transferring a folder. Either way, exactly one may be fixed.
18    fn chosen_choice(&self) -> Option<&str>;
19
20    /// Observes every choice the request offers, in the order it offers them.
21    ///
22    /// A media item offers what extraction discovered, and its stream roles state which of them
23    /// is *preferred* when none is fixed; they never hide one the source states. A folder offers every way it may be transferred.
24    fn selectable_choices(&self) -> impl Iterator<Item = &str>;
25
26    /// Observes what one offered choice states about itself, when it states anything.
27    ///
28    /// A choice a reader would not recognize by name says what it does; one described by what it
29    /// carries is read through that description instead.
30    fn choice_summary(&self, choice: &str) -> Option<&str>;
31}
32
33/// Defines the first-order observation stream of format discovery.
34///
35/// An observation is a method, so the reified stream is generated from this vocabulary rather than
36/// written out. An interpreter states what each observation *means* and never restates the shape.
37#[trait_algebra(derive(Clone, Debug, PartialEq, Eq))]
38pub trait FormatDiscovery {
39    /// Represents one described selectable format.
40    type Format;
41
42    /// Denotes that an interpreter started source inspection.
43    fn started(&self);
44
45    /// Supplies the described formats in extractor preference order.
46    fn available(&self, formats: Vec<Self::Format>);
47
48    /// Denotes source inspection failure.
49    fn failed(&self, message: String);
50}
51
52/// Derives the media one request selects from the choices it states.
53#[ext(name = RequestSelectionExt)]
54pub impl<This> This
55where
56    This: FormatPredicateAlg + FormatSelectionAlg,
57{
58    /// Defines the selection one request's own choices state.
59    fn request_selection(&self, options: &impl RequestOptionsAlg) -> This::Selection {
60        let predicate = match options.chosen_choice() {
61            // A fixed identity names exactly one format, so the stream roles add nothing to it.
62            Some(choice) => self.format_id(choice),
63            // A request choosing no media role is not one this program retrieves, so it asks for
64            // the whole thing and lets selection refuse it.
65            None => self.stream_role_format(options.media_streams().unwrap_or(MediaStreams::AudioVideo)),
66        };
67        self.best_format(predicate)
68    }
69}
70
71/// Derives the format predicate one set of stream roles requires.
72#[ext(name = MediaStreamsExt)]
73pub impl<This> This
74where
75    This: FormatPredicateAlg,
76{
77    /// Defines the predicate accepting exactly the formats those roles require.
78    fn stream_role_format(&self, streams: MediaStreams) -> This::Predicate {
79        match streams {
80            MediaStreams::AudioVideo => self.progressive_format(),
81            MediaStreams::Audio => self.audio_only_format(),
82            MediaStreams::Video => self.video_only_format(),
83        }
84    }
85}
86
87/// Denotes what performs one request.
88///
89/// A request is either run by naming a program and reading what it writes, or retrieved by this
90/// program itself from wherever the source that claimed it keeps what it names. How many files
91/// come to rest, and whether they land in a folder, follows from what the request chose — not
92/// from which of these performs it.
93#[derive(Clone, Copy, Debug, PartialEq, Eq)]
94pub enum Performer {
95    /// Denotes a request performed by naming a program and reading what it writes.
96    Program,
97    /// Denotes a request this program retrieves for itself.
98    Retrieval,
99}
100
101/// Selects the stream roles a request prefers when it fixes no format identity.
102#[derive(Clone, Copy, Debug, PartialEq, Eq)]
103pub enum MediaStreams {
104    /// Selects a progressive format containing both audio and video.
105    AudioVideo,
106    /// Selects a format containing audio and no video.
107    Audio,
108    /// Selects a format containing video and no audio.
109    Video,
110}
111
112impl MediaStreams {
113    /// States the roles a request may prefer, in the order they are offered.
114    pub const OFFERED: [Self; 3] = [Self::AudioVideo, Self::Video, Self::Audio];
115}