servo_media_derive/
lib.rs

1#![recursion_limit = "128"]
2
3extern crate proc_macro;
4extern crate proc_macro2;
5extern crate syn;
6#[macro_use]
7extern crate quote;
8
9use proc_macro::TokenStream;
10
11#[proc_macro_derive(AudioScheduledSourceNode)]
12pub fn audio_scheduled_source_node(input: TokenStream) -> TokenStream {
13    let ast: syn::DeriveInput = syn::parse(input).unwrap();
14    let gen = impl_audio_scheduled_source_node(&ast);
15    gen.into()
16}
17
18fn impl_audio_scheduled_source_node(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
19    let name = &ast.ident;
20    quote! {
21        impl #name {
22            fn should_play_at(&mut self, tick: Tick) -> ShouldPlay {
23                let start = if let Some(start) = self.start_at {
24                    start
25                } else {
26                    return ShouldPlay::No;
27                };
28
29                let frame_end = tick + Tick::FRAMES_PER_BLOCK;
30                if tick < start {
31                    if frame_end < start {
32                        ShouldPlay::No
33                    } else {
34                        let delta_start = start - tick;
35                        if let Some(stop) = self.stop_at {
36                            if stop <= start {
37                                self.maybe_trigger_onended_callback();
38                                return ShouldPlay::No;
39                            }
40                            if stop > frame_end {
41                                ShouldPlay::Between(delta_start, Tick::FRAMES_PER_BLOCK)
42                            } else {
43                                self.maybe_trigger_onended_callback();
44                                ShouldPlay::Between(delta_start, stop - tick)
45                            }
46                        } else {
47                            ShouldPlay::Between(delta_start, Tick::FRAMES_PER_BLOCK)
48                        }
49                    }
50                } else {
51                    let stop = if let Some(stop) = self.stop_at {
52                        stop
53                    } else {
54                        return ShouldPlay::Between(Tick(0), Tick::FRAMES_PER_BLOCK);
55                    };
56                    if stop > frame_end {
57                        ShouldPlay::Between(Tick(0), Tick::FRAMES_PER_BLOCK)
58                    } else if stop < tick {
59                        self.maybe_trigger_onended_callback();
60                        ShouldPlay::No
61                    } else {
62                        self.maybe_trigger_onended_callback();
63                        ShouldPlay::Between(Tick(0), stop - tick)
64                    }
65                }
66            }
67
68            fn start(&mut self, tick: Tick) -> bool {
69                // We can only allow a single call to `start` and always before
70                // any `stop` calls.
71                if self.start_at.is_some() || self.stop_at.is_some() {
72                    return false;
73                }
74                self.start_at = Some(tick);
75                true
76            }
77
78            fn stop(&mut self, tick: Tick) -> bool {
79                // We can only allow calls to `stop` after `start` is called.
80                if self.start_at.is_none() {
81                    return false;
82                }
83                // If `stop` is called again after already having been called,
84                // the last invocation will be the only one applied.
85                self.stop_at = Some(tick);
86                true
87            }
88
89            fn maybe_trigger_onended_callback(&mut self) {
90                // We cannot have an end without a start.
91                if self.start_at.is_none() {
92                    return;
93                }
94                if let Some(cb) = self.onended_callback.take() {
95                    cb.0()
96                }
97            }
98
99            fn handle_source_node_message(&mut self, message: AudioScheduledSourceNodeMessage, sample_rate: f32) {
100                match message {
101                    AudioScheduledSourceNodeMessage::Start(when) => {
102                        self.start(Tick::from_time(when, sample_rate));
103                    }
104                    AudioScheduledSourceNodeMessage::Stop(when) => {
105                        self.stop(Tick::from_time(when, sample_rate));
106                    }
107                    AudioScheduledSourceNodeMessage::RegisterOnEndedCallback(callback) => {
108                        self.onended_callback = Some(callback);
109                    }
110                }
111            }
112        }
113    }
114}
115
116#[proc_macro_derive(AudioNodeCommon)]
117pub fn channel_info(input: TokenStream) -> TokenStream {
118    let ast: syn::DeriveInput = syn::parse(input).unwrap();
119    let name = &ast.ident;
120    let gen = quote! {
121        impl crate::node::AudioNodeCommon for #name {
122            fn channel_info(&self) -> &crate::node::ChannelInfo {
123                &self.channel_info
124            }
125
126            fn channel_info_mut(&mut self) -> &mut crate::node::ChannelInfo {
127                &mut self.channel_info
128            }
129        }
130    };
131    gen.into()
132}