clap_clap/ext/
latency.rs

1use crate::plugin::Plugin;
2
3pub trait Latency<P>
4where
5    P: Plugin,
6{
7    /// Return the plugin latency in samples.
8    fn get(plugin: &P) -> u32;
9}
10
11impl<P: Plugin> Latency<P> for () {
12    fn get(_: &P) -> u32 {
13        0
14    }
15}
16
17pub(crate) use ffi::PluginLatency;
18
19use crate::{ffi::clap_host_latency, host::Host};
20
21mod ffi {
22    use std::marker::PhantomData;
23
24    use crate::{
25        ext::latency::Latency,
26        ffi::{clap_plugin, clap_plugin_latency},
27        plugin::{ClapPlugin, Plugin},
28    };
29
30    extern "C-unwind" fn get<E, P>(plugin: *const clap_plugin) -> u32
31    where
32        E: Latency<P>,
33        P: Plugin,
34    {
35        if plugin.is_null() {
36            return 0;
37        }
38        // SAFETY: We just checked that the pointer is non-null and the plugin
39        // has been obtained from host and is tied to type P.
40        let mut clap_plugin = unsafe { ClapPlugin::<P>::new_unchecked(plugin) };
41
42        // SAFETY: This function is called on the main thread.
43        // It is guaranteed that we are the only function accessing the plugin now.
44        // So the mutable reference to plugin for the duration of this call is
45        // safe.
46        let plugin = unsafe { clap_plugin.plugin() };
47
48        E::get(plugin)
49    }
50
51    pub struct PluginLatency<P> {
52        #[allow(unused)]
53        clap_plugin_latency: clap_plugin_latency,
54        _marker: PhantomData<P>,
55    }
56
57    impl<P: Plugin> PluginLatency<P> {
58        pub fn new<E: Latency<P>>(_: E) -> Self {
59            Self {
60                clap_plugin_latency: clap_plugin_latency {
61                    get: Some(get::<E, P>),
62                },
63                _marker: PhantomData,
64            }
65        }
66    }
67}
68
69#[derive(Debug)]
70pub struct HostLatency<'a> {
71    host: &'a Host,
72    clap_host_latency: &'a clap_host_latency,
73}
74
75impl<'a> HostLatency<'a> {
76    /// # Safety
77    ///
78    /// All extension interface function pointers must be non-null (Some), and
79    /// the functions must be thread-safe.
80    pub(crate) const unsafe fn new_unchecked(
81        host: &'a Host,
82        clap_host_latency: &'a clap_host_latency,
83    ) -> Self {
84        Self {
85            host,
86            clap_host_latency,
87        }
88    }
89
90    pub fn changed(&self) {
91        // SAFETY: By construction, the pointer to the interface function: changed() is
92        // non-null.
93        unsafe {
94            self.clap_host_latency.changed.unwrap()(self.host.clap_host());
95        }
96    }
97}