clack_plugin/entry/single.rs
1#![deny(unsafe_code)]
2
3use crate::entry::prelude::*;
4use crate::prelude::*;
5use std::ffi::CStr;
6use std::marker::PhantomData;
7
8/// An [`Entry`] that only exposes a single plugin type to the host.
9///
10/// This is a simplified entry type, which only requires the simple [`DefaultPluginFactory`] trait to be
11/// implemented by the user, and implements an entry and plugin factory around it.
12///
13/// This entry type exists purely for convenience of the users in the common case of having a single
14/// plugin type to expose to the host.
15///
16/// If you actually need to expose more plugin types, or to customize the entry's behavior in some
17/// other way, see the [`Entry`] trait documentation for an example on how to implement your own
18/// custom entry.
19///
20/// # Example
21///
22/// ```
23/// use clack_plugin::entry::DefaultPluginFactory;
24/// use clack_plugin::prelude::*;
25///
26/// pub struct MyPlugin;
27///
28/// impl Plugin for MyPlugin {
29/// type AudioProcessor<'a> = ();
30/// type Shared<'a> = ();
31/// type MainThread<'a> = ();
32/// }
33///
34/// impl DefaultPluginFactory for MyPlugin {
35/// fn get_descriptor() -> PluginDescriptor {
36/// PluginDescriptor::new("my.plugin", "My Plugin")
37/// }
38///
39/// fn new_shared<'a>(
40/// _host: HostSharedHandle<'a>
41/// ) -> Result<Self::Shared<'a>, PluginError> {
42/// Ok(())
43/// }
44///
45/// fn new_main_thread<'a>(
46/// host: HostMainThreadHandle<'a>,
47/// shared: &'a Self::Shared<'a>
48/// ) -> Result<Self::MainThread<'a>, PluginError> {
49/// Ok(())
50/// }
51/// }
52///
53/// clack_export_entry!(SinglePluginEntry::<MyPlugin>);
54/// ```
55pub struct SinglePluginEntry<P: DefaultPluginFactory> {
56 plugin_factory: PluginFactoryWrapper<SinglePluginFactory<P>>,
57}
58
59impl<P: DefaultPluginFactory> Entry for SinglePluginEntry<P> {
60 fn new(_plugin_path: Option<&CStr>) -> Result<Self, EntryLoadError> {
61 Ok(Self {
62 plugin_factory: PluginFactoryWrapper::new(SinglePluginFactory {
63 descriptor: P::get_descriptor(),
64 _plugin: PhantomData,
65 }),
66 })
67 }
68
69 #[inline]
70 fn declare_factories<'a>(&'a self, builder: &mut EntryFactories<'a>) {
71 builder.register_factory(&self.plugin_factory);
72 }
73}
74
75struct SinglePluginFactory<P> {
76 descriptor: PluginDescriptor,
77 _plugin: PhantomData<fn() -> P>,
78}
79
80impl<P: DefaultPluginFactory> PluginFactoryImpl for SinglePluginFactory<P> {
81 #[inline]
82 fn plugin_count(&self) -> u32 {
83 1
84 }
85
86 #[inline]
87 fn plugin_descriptor(&self, index: u32) -> Option<&PluginDescriptor> {
88 match index {
89 0 => Some(&self.descriptor),
90 _ => None,
91 }
92 }
93
94 #[inline]
95 fn create_plugin<'a>(
96 &'a self,
97 host_info: HostInfo<'a>,
98 plugin_id: &CStr,
99 ) -> Option<PluginInstance<'a>> {
100 if plugin_id == self.descriptor.id().unwrap_or_default() {
101 Some(PluginInstance::new::<P>(
102 host_info,
103 &self.descriptor,
104 P::new_shared,
105 P::new_main_thread,
106 ))
107 } else {
108 None
109 }
110 }
111}
112
113/// An optional trait used by [`SinglePluginEntry`] that provides simplified, methods for generic
114/// plugin factories.
115///
116/// Implementing this trait is optional: you can disregard it completely if you use a custom
117/// factory, which also allows you to pass additional parameters to these methods, for e.g. sharing
118/// data across multiple instances.
119///
120/// See the [`SinglePluginEntry`] documentation for more information and examples.
121pub trait DefaultPluginFactory: Plugin {
122 /// Returns a new Plugin Descriptor, which contains metadata about the plugin, such as its name,
123 /// stable identifier, and more.
124 ///
125 /// See the [`PluginDescriptor`] type's documentation for more information.
126 fn get_descriptor() -> PluginDescriptor;
127
128 /// Creates a new instance of this shared data.
129 ///
130 /// This struct receives a thread-safe host handle that can be stored for the lifetime of the plugin.
131 ///
132 /// # Errors
133 /// This operation may fail for any reason, in which case `Err` is returned and the plugin is
134 /// not instantiated.
135 fn new_shared(host: HostSharedHandle<'_>) -> Result<Self::Shared<'_>, PluginError>;
136
137 /// Creates a new instance of the plugin's main thread.
138 ///
139 /// This struct receives an exclusive host handle that can be stored for the lifetime of the plugin.
140 ///
141 /// # Errors
142 /// This operation may fail for any reason, in which case `Err` is returned and the plugin is
143 /// not instantiated.
144 fn new_main_thread<'a>(
145 host: HostMainThreadHandle<'a>,
146 shared: &'a Self::Shared<'a>,
147 ) -> Result<Self::MainThread<'a>, PluginError>;
148}