Skip to main content

clack_plugin/factory/
plugin.rs

1//! The plugin factory type, which is the entry point for hosts to discover and instantiate plugins.
2//!
3//! In CLAP, the Plugin Factory is the main factory type (and at the time of writing, the only
4//! stable standard one). Its purpose is to expose to the host a list of all the plugin types
5//! included in this file, and to allow the host to instantiate them.
6//!
7//! See the [`factory` module documentation](crate::factory) to learn more about factories.
8
9use super::*;
10use crate::host::HostInfo;
11use crate::plugin::{PluginDescriptor, PluginInstance};
12use clack_common::factory::plugin::PluginFactory;
13use clap_sys::factory::plugin_factory::clap_plugin_factory;
14use clap_sys::host::clap_host;
15use clap_sys::plugin::{clap_plugin, clap_plugin_descriptor};
16use std::ffi::CStr;
17use std::ptr::NonNull;
18
19/// A wrapper around a given [`PluginFactoryImpl`] implementation.
20///
21/// This wrapper is required in order to expose a C FFI-compatible factory to the host, and is what
22/// needs to be exposed by an [`Entry`](crate::entry::Entry).
23pub struct PluginFactoryWrapper<F> {
24    inner: FactoryWrapper<clap_plugin_factory, F>,
25}
26
27impl<F: PluginFactoryImpl> PluginFactoryWrapper<F> {
28    const RAW: clap_plugin_factory = clap_plugin_factory {
29        get_plugin_count: Some(Self::get_plugin_count),
30        get_plugin_descriptor: Some(Self::get_plugin_descriptor),
31        create_plugin: Some(Self::create_plugin),
32    };
33
34    /// Wraps a given [`PluginFactoryImpl`] instance.
35    pub const fn new(factory: F) -> Self {
36        Self {
37            inner: FactoryWrapper::new(Self::RAW, factory),
38        }
39    }
40
41    /// Returns a shared reference to the wrapped [`PluginFactoryImpl`].
42    #[inline]
43    pub const fn factory(&self) -> &F {
44        self.inner.factory()
45    }
46
47    /// Returns a raw CLAP plugin factory pointer, ready to be used by the host.
48    #[inline]
49    pub fn as_raw_ptr(&self) -> *const clap_plugin_factory {
50        self.inner.as_raw_ptr()
51    }
52
53    #[allow(clippy::missing_safety_doc)]
54    unsafe extern "C" fn get_plugin_count(factory: *const clap_plugin_factory) -> u32 {
55        FactoryWrapper::<clap_plugin_factory, F>::handle(factory, |factory| {
56            Ok(factory.plugin_count())
57        })
58        .unwrap_or(0)
59    }
60
61    #[allow(clippy::missing_safety_doc)]
62    unsafe extern "C" fn get_plugin_descriptor(
63        factory: *const clap_plugin_factory,
64        index: u32,
65    ) -> *const clap_plugin_descriptor {
66        FactoryWrapper::<clap_plugin_factory, F>::handle(factory, |factory| {
67            match factory.plugin_descriptor(index) {
68                None => Ok(core::ptr::null()),
69                Some(d) => Ok(d.as_raw()),
70            }
71        })
72        .unwrap_or(core::ptr::null())
73    }
74
75    #[allow(clippy::missing_safety_doc)]
76    unsafe extern "C" fn create_plugin(
77        factory: *const clap_plugin_factory,
78        clap_host: *const clap_host,
79        plugin_id: *const std::os::raw::c_char,
80    ) -> *const clap_plugin {
81        FactoryWrapper::<clap_plugin_factory, F>::handle(factory, |factory| {
82            let plugin_id = CStr::from_ptr(plugin_id);
83            let clap_host = NonNull::new(clap_host as *mut _)
84                .ok_or(FactoryWrapperError::NulPtr("clap_host"))?;
85
86            let host_info = HostInfo::from_raw(clap_host);
87
88            match factory.create_plugin(host_info, plugin_id) {
89                None => Ok(core::ptr::null()),
90                Some(instance) => Ok(instance.into_owned_ptr()),
91            }
92        })
93        .unwrap_or(core::ptr::null())
94    }
95}
96
97// SAFETY: The returned raw implementation matches the spec for clap_plugin_factory
98unsafe impl<'a, F: PluginFactoryImpl + 'a> FactoryImplementation<'a> for PluginFactoryWrapper<F> {
99    type Factory = PluginFactory<'a>;
100    type Wrapped = F;
101
102    #[inline]
103    fn wrapper(&self) -> &FactoryWrapper<clap_plugin_factory, F> {
104        &self.inner
105    }
106}
107
108/// A Plugin Factory implementation.
109///
110/// See the [module documentation](self) to learn more about the role of a Plugin Factory.
111///
112/// # Example
113///
114/// The following example shows how to implement a basic, single-plugin factory.
115///
116/// ```
117/// use std::ffi::CStr;
118/// use clack_plugin::entry::prelude::*;
119/// use clack_plugin::prelude::*;
120///
121/// pub struct MyPlugin;
122///
123/// impl Plugin for MyPlugin {
124///     type AudioProcessor<'a> = ();
125///     type Shared<'a> = ();
126///     type MainThread<'a> = ();
127/// }
128///
129/// pub struct MyPluginFactory {
130///     plugin_descriptor: PluginDescriptor
131/// }
132///
133/// impl PluginFactoryImpl for MyPluginFactory {
134///     fn plugin_count(&self) -> u32 {
135///         1 // We only have a single plugin
136///     }
137///
138///     fn plugin_descriptor(&self, index: u32) -> Option<&PluginDescriptor> {
139///         match index {
140///             0 => Some(&self.plugin_descriptor),
141///             _ => None
142///         }
143///     }
144///
145///     fn create_plugin<'a>(&'a self, host_info: HostInfo<'a>, plugin_id: &CStr) -> Option<PluginInstance<'a>> {
146///         if plugin_id == self.plugin_descriptor.id().unwrap_or_default() {
147///             Some(PluginInstance::new::<MyPlugin>(
148///                 host_info,
149///                 &self.plugin_descriptor,
150///                 |_host| Ok(()) /* Create the shared struct */,
151///                 |_host, _shared| Ok(()) /* Create the main thread struct */,
152///             ))
153///         } else {
154///             None
155///         }
156///     }
157/// }
158/// ```
159pub trait PluginFactoryImpl: Send + Sync {
160    /// Returns the number of plugins exposed by this factory.
161    fn plugin_count(&self) -> u32;
162
163    /// Returns the [`PluginDescriptor`] of the plugin that is assigned the given index.
164    ///
165    /// Hosts will usually call this method repeatedly with every index from 0 to the total returned
166    /// by [`plugin_count`](PluginFactoryImpl::plugin_count), in order to discover all the plugins
167    /// exposed by this factory.
168    ///
169    /// If the given index is out of bounds, or in general does not match any given plugin, this
170    /// returns [`None`].
171    fn plugin_descriptor(&self, index: u32) -> Option<&PluginDescriptor>;
172
173    /// Creates a new plugin instance for the plugin type matching the given `plugin_id`.
174    ///
175    /// If the given `plugin_id` matches against one of the plugin this factory manages,
176    /// implementors of this trait then use the [`PluginInstance::new`] method to instantiate the
177    /// corresponding plugin implementation.
178    ///
179    /// If the given `plugin_id` does not match any known plugins to this factory, this method
180    /// returns [`None`].
181    fn create_plugin<'a>(
182        &'a self,
183        host_info: HostInfo<'a>,
184        plugin_id: &CStr,
185    ) -> Option<PluginInstance<'a>>;
186}