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. // On Windows `win32-dpi-aware` is a special value informing the host that the plugin is // DPI-aware. // TODO: Is this actually what we want? What happens if we don't add it? If this means that // we need to do our own DPI handling instead of the host passing a scale then we // don't want that of course. #[cfg(target_os = "windows")] descriptor .clap_features .push(CString::new("win32-dpi-aware").unwrap()); 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() } }