diff --git a/src/wrapper/clap.rs b/src/wrapper/clap.rs index 6804f67e..cc991518 100644 --- a/src/wrapper/clap.rs +++ b/src/wrapper/clap.rs @@ -1,3 +1,4 @@ +mod descriptor; mod factory; mod plugin; diff --git a/src/wrapper/clap/descriptor.rs b/src/wrapper/clap/descriptor.rs new file mode 100644 index 00000000..cfaf708a --- /dev/null +++ b/src/wrapper/clap/descriptor.rs @@ -0,0 +1,98 @@ +use clap_sys::plugin::clap_plugin_descriptor; +use clap_sys::version::CLAP_VERSION; +use std::ffi::{CStr, CString}; +use std::marker::PhantomData; +use std::mem::MaybeUninit; +use std::os::raw::c_char; +use std::ptr; + +use crate::plugin::ClapPlugin; + +/// A static descriptor for a plugin. This is used in both the descriptor and on the plugin object +/// itself. +/// +/// This cannot be cloned as [Self::clap_features_ptrs] contains pointers to [Self::clap_features]. +pub struct PluginDescriptor { + // We need [CString]s for all of `ClapPlugin`'s `&str` fields + clap_id: CString, + name: CString, + vendor: CString, + url: CString, + clap_manual_url: CString, + clap_support_url: CString, + version: CString, + clap_description: CString, + clap_features: Vec, + clap_features_ptrs: MaybeUninit>, + + /// We only support a single plugin per descriptor right now, so we'll fill in the plugin + /// descriptor upfront. We also need to initialize the `CString` fields above first before we + /// can initialize this plugin descriptor. + plugin_descriptor: MaybeUninit, + + /// The plugin's type. + _phantom: PhantomData

, +} + +impl Default for PluginDescriptor

{ + fn default() -> Self { + let mut descriptor = Self { + clap_id: CString::new(P::CLAP_ID).expect("`CLAP_ID` contained null bytes"), + name: CString::new(P::NAME).expect("`NAME` contained null bytes"), + vendor: CString::new(P::VENDOR).expect("`VENDOR` contained null bytes"), + url: CString::new(P::URL).expect("`URL` contained null bytes"), + clap_manual_url: CString::new(P::CLAP_MANUAL_URL) + .expect("`CLAP_MANUAL_URL` contained null bytes"), + clap_support_url: CString::new(P::CLAP_SUPPORT_URL) + .expect("`CLAP_SUPPORT_URL` contained null bytes"), + version: CString::new(P::VERSION).expect("`VERSION` contained null bytes"), + clap_description: CString::new(P::CLAP_DESCRIPTION) + .expect("`CLAP_DESCRIPTION` contained null bytes"), + clap_features: P::CLAP_FEATURES + .iter() + .map(|s| CString::new(*s).expect("`CLAP_FEATURES` contained null bytes")) + .collect(), + clap_features_ptrs: MaybeUninit::uninit(), + plugin_descriptor: MaybeUninit::uninit(), + _phantom: PhantomData, + }; + + // The keyword list is an environ-like list of char pointers terminated by a null pointer + let mut clap_features_ptrs: Vec<*const c_char> = descriptor + .clap_features + .iter() + .map(|feature| feature.as_ptr()) + .collect(); + clap_features_ptrs.push(ptr::null()); + descriptor.clap_features_ptrs.write(clap_features_ptrs); + + // We couldn't initialize this directly because of all the CStrings + descriptor.plugin_descriptor.write(clap_plugin_descriptor { + clap_version: CLAP_VERSION, + id: descriptor.clap_id.as_ptr(), + name: descriptor.name.as_ptr(), + vendor: descriptor.vendor.as_ptr(), + url: descriptor.url.as_ptr(), + manual_url: descriptor.clap_manual_url.as_ptr(), + support_url: descriptor.clap_support_url.as_ptr(), + version: descriptor.version.as_ptr(), + description: descriptor.clap_description.as_ptr(), + features: unsafe { descriptor.clap_features_ptrs.assume_init_ref() }.as_ptr(), + }); + + descriptor + } +} + +unsafe impl Send for PluginDescriptor

{} +unsafe impl Sync for PluginDescriptor

{} + +impl PluginDescriptor

{ + pub fn clap_plugin_descriptor(&self) -> &clap_plugin_descriptor { + unsafe { self.plugin_descriptor.assume_init_ref() } + } + + pub fn clap_id(&self) -> &CStr { + self.clap_id.as_c_str() + } +} diff --git a/src/wrapper/clap/factory.rs b/src/wrapper/clap/factory.rs index b6c4d660..fc3e3656 100644 --- a/src/wrapper/clap/factory.rs +++ b/src/wrapper/clap/factory.rs @@ -1,13 +1,11 @@ use clap_sys::host::clap_host; use clap_sys::plugin::{clap_plugin, clap_plugin_descriptor}; use clap_sys::plugin_factory::clap_plugin_factory; -use clap_sys::version::CLAP_VERSION; -use std::ffi::{CStr, CString}; -use std::marker::PhantomData; -use std::mem::MaybeUninit; +use std::ffi::CStr; use std::os::raw::c_char; use std::ptr; +use super::descriptor::PluginDescriptor; use super::plugin::Plugin; use crate::ClapPlugin; @@ -19,92 +17,22 @@ pub struct Factory { // Keep the vtable as the first field so we can do a simple pointer cast pub clap_plugin_factory: clap_plugin_factory, - // We need [CString]s for all of `ClapPlugin`'s `&str` fields - clap_id: CString, - name: CString, - vendor: CString, - url: CString, - clap_manual_url: CString, - clap_support_url: CString, - version: CString, - clap_description: CString, - clap_features: Vec, - clap_features_ptrs: MaybeUninit, - - /// We only support a single plugin per factory right now, so we'll fill in the plugin - /// descriptor upfront. We also need to initialize the `CString` fields above first before we - /// can initialize this plugin descriptor. - plugin_descriptor: MaybeUninit, - - /// The type will be used for constructing plugin instances later. - _phantom: PhantomData

, + plugin_descriptor: PluginDescriptor

, } -/// Needed for the Send+Sync implementation for lazy_static. -struct CStrPtrs(Vec<*const c_char>); - impl Default for Factory

{ fn default() -> Self { - let mut factory = Self { + Self { clap_plugin_factory: clap_plugin_factory { get_plugin_count: Self::get_plugin_count, get_plugin_descriptor: Self::get_plugin_descriptor, create_plugin: Self::create_plugin, }, - clap_id: CString::new(P::CLAP_ID).expect("`CLAP_ID` contained null bytes"), - name: CString::new(P::NAME).expect("`NAME` contained null bytes"), - vendor: CString::new(P::VENDOR).expect("`VENDOR` contained null bytes"), - url: CString::new(P::URL).expect("`URL` contained null bytes"), - clap_manual_url: CString::new(P::CLAP_MANUAL_URL) - .expect("`CLAP_MANUAL_URL` contained null bytes"), - clap_support_url: CString::new(P::CLAP_SUPPORT_URL) - .expect("`CLAP_SUPPORT_URL` contained null bytes"), - version: CString::new(P::VERSION).expect("`VERSION` contained null bytes"), - clap_description: CString::new(P::CLAP_DESCRIPTION) - .expect("`CLAP_DESCRIPTION` contained null bytes"), - clap_features: P::CLAP_FEATURES - .iter() - .map(|s| CString::new(*s).expect("`CLAP_FEATURES` contained null bytes")) - .collect(), - clap_features_ptrs: MaybeUninit::uninit(), - plugin_descriptor: MaybeUninit::uninit(), - _phantom: PhantomData, - }; - - // The keyword list is an environ-like list of char pointers terminated by a null pointer - let mut clap_features_ptrs: Vec<*const c_char> = factory - .clap_features - .iter() - .map(|feature| feature.as_ptr()) - .collect(); - clap_features_ptrs.push(ptr::null()); - factory - .clap_features_ptrs - .write(CStrPtrs(clap_features_ptrs)); - - // We couldn't initialize this directly because of all the CStrings - factory.plugin_descriptor.write(clap_plugin_descriptor { - clap_version: CLAP_VERSION, - id: factory.clap_id.as_ptr(), - name: factory.name.as_ptr(), - vendor: factory.vendor.as_ptr(), - url: factory.url.as_ptr(), - manual_url: factory.clap_manual_url.as_ptr(), - support_url: factory.clap_support_url.as_ptr(), - version: factory.version.as_ptr(), - description: factory.clap_description.as_ptr(), - features: unsafe { factory.clap_features_ptrs.assume_init_ref() } - .0 - .as_ptr(), - }); - - factory + plugin_descriptor: PluginDescriptor::default(), + } } } -unsafe impl Send for CStrPtrs {} -unsafe impl Sync for CStrPtrs {} - impl Factory

{ unsafe extern "C" fn get_plugin_count(_factory: *const clap_plugin_factory) -> u32 { 1 @@ -117,7 +45,7 @@ impl Factory

{ let factory = &*(factory as *const Self); if index == 0 { - factory.plugin_descriptor.assume_init_ref() + factory.plugin_descriptor.clap_plugin_descriptor() } else { ptr::null() } @@ -130,7 +58,8 @@ impl Factory

{ ) -> *const clap_plugin { let factory = &*(factory as *const Self); - if !plugin_id.is_null() && CStr::from_ptr(plugin_id) == factory.clap_id.as_c_str() { + if !plugin_id.is_null() && CStr::from_ptr(plugin_id) == factory.plugin_descriptor.clap_id() + { &Box::leak(Box::new(Plugin::

::new(host))).clap_plugin } else { ptr::null()