clack_common/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 crate::factory::{Factory, RawFactoryPointer};
10use crate::plugin::PluginDescriptor;
11use clap_sys::factory::plugin_factory::{CLAP_PLUGIN_FACTORY_ID, clap_plugin_factory};
12use std::ffi::CStr;
13use std::iter::FusedIterator;
14
15/// A Plugin Factory.
16///
17/// See the [module documentation](self) to learn more about the role of a Plugin Factory.
18#[derive(Copy, Clone)]
19#[allow(dead_code)]
20pub struct PluginFactory<'a>(RawFactoryPointer<'a, clap_plugin_factory>);
21
22// SAFETY: clap_plugin_factory is the type matching the CLAP_PLUGIN_FACTORY_ID factory ID.
23unsafe impl<'a> Factory<'a> for PluginFactory<'a> {
24 const IDENTIFIERS: &'static [&'static CStr] = &[CLAP_PLUGIN_FACTORY_ID];
25 type Raw = clap_plugin_factory;
26
27 #[inline]
28 unsafe fn from_raw(raw: RawFactoryPointer<'a, Self::Raw>) -> Self {
29 Self(raw)
30 }
31}
32
33impl<'a> PluginFactory<'a> {
34 /// Returns this factory as a raw pointer to its C-FFI compatible raw CLAP structure
35 #[inline]
36 pub const fn raw(&self) -> RawFactoryPointer<'a, clap_plugin_factory> {
37 self.0
38 }
39
40 /// Returns the number of plugin descriptors exposed by this plugin factory.
41 #[inline]
42 pub fn plugin_count(&self) -> u32 {
43 match self.0.get().get_plugin_count {
44 None => 0,
45 // SAFETY: this type ensures the function pointer is valid
46 Some(count) => unsafe { count(self.0.as_ptr()) },
47 }
48 }
49
50 /// Returns the [`PluginDescriptor`s](PluginDescriptor) exposed by this plugin
51 /// factory at a given index, or `None` if there is no plugin descriptor at the given index.
52 ///
53 /// Implementations on the plugin-side *should* return a descriptor for any index strictly less
54 /// than [`plugin_count`](PluginFactory::plugin_count), but this is not a guarantee.
55 ///
56 /// See also the [`plugin_descriptors`](PluginFactory::plugin_descriptors) method for a
57 /// convenient iterator of all the plugin descriptors exposed by this factory.
58 #[inline]
59 pub fn plugin_descriptor(&self, index: u32) -> Option<&'a PluginDescriptor> {
60 let get_plugin_descriptor = self.0.get().get_plugin_descriptor?;
61 // SAFETY: descriptor is guaranteed not to outlive the entry
62 unsafe { get_plugin_descriptor(self.0.as_ptr(), index).as_ref() }
63 // SAFETY: this descriptor is guaranteed to be valid by the spec
64 .map(|d| unsafe { PluginDescriptor::from_raw(d) })
65 }
66
67 /// Returns an iterator of all the [`PluginDescriptor`s](PluginDescriptor) exposed by this
68 /// plugin factory.
69 ///
70 /// For convenience, the [`&PluginFactory`](PluginFactory) type implements the
71 /// [`IntoIterator`] trait, which also returns this iterator.
72 ///
73 /// See also the [`plugin_descriptor`](PluginFactory::plugin_descriptor) method to retrieve
74 /// a plugin descriptor at a specific index.
75 #[inline]
76 pub fn plugin_descriptors(&self) -> PluginDescriptorsIter<'a> {
77 PluginDescriptorsIter {
78 factory: *self,
79 range: 0..self.plugin_count(),
80 }
81 }
82}
83
84/// Returns an iterator of all the [`PluginDescriptor`s](PluginDescriptor) exposed by this plugin
85/// factory.
86impl<'a> IntoIterator for PluginFactory<'a> {
87 type Item = &'a PluginDescriptor;
88 type IntoIter = PluginDescriptorsIter<'a>;
89
90 #[inline]
91 fn into_iter(self) -> Self::IntoIter {
92 self.plugin_descriptors()
93 }
94}
95
96/// An [`Iterator`] over all the [`PluginDescriptor`s](PluginDescriptor) exposed by a
97/// plugin factory.
98///
99/// See the [`PluginFactory::plugin_descriptors`] method that produces this iterator.
100pub struct PluginDescriptorsIter<'a> {
101 factory: PluginFactory<'a>,
102 range: core::ops::Range<u32>,
103}
104
105impl<'a> Iterator for PluginDescriptorsIter<'a> {
106 type Item = &'a PluginDescriptor;
107
108 #[inline]
109 fn next(&mut self) -> Option<Self::Item> {
110 loop {
111 let next = self.range.next()?;
112
113 if let Some(descriptor) = self.factory.plugin_descriptor(next) {
114 return Some(descriptor);
115 }
116 }
117 }
118
119 #[inline]
120 fn size_hint(&self) -> (usize, Option<usize>) {
121 self.range.size_hint()
122 }
123}
124
125impl ExactSizeIterator for PluginDescriptorsIter<'_> {
126 #[inline]
127 fn len(&self) -> usize {
128 self.range.len()
129 }
130}
131
132impl FusedIterator for PluginDescriptorsIter<'_> {}
133
134impl DoubleEndedIterator for PluginDescriptorsIter<'_> {
135 #[inline]
136 fn next_back(&mut self) -> Option<Self::Item> {
137 loop {
138 let next = self.range.next_back()?;
139
140 if let Some(descriptor) = self.factory.plugin_descriptor(next) {
141 return Some(descriptor);
142 }
143 }
144 }
145}