Skip to main content

nice_plug/wrapper/clap/
descriptor.rs

1use clap_sys::plugin::clap_plugin_descriptor;
2use clap_sys::version::CLAP_VERSION;
3use std::ffi::{CStr, CString};
4use std::os::raw::c_char;
5
6use crate::wrapper::clap::ClapPlugin;
7
8/// A static descriptor for a plugin. This is used in both the descriptor and on the plugin object
9/// itself.
10///
11/// This cannot be cloned as `clap_features_ptrs` contains pointers to `clap_features`.
12pub struct PluginDescriptor {
13    // We need [CString]s for all of `ClapPlugin`'s `&str` fields
14    clap_id: CString,
15    name: CString,
16    vendor: CString,
17    url: CString,
18    version: CString,
19    clap_manual_url: Option<CString>,
20    clap_support_url: Option<CString>,
21    clap_description: Option<CString>,
22    clap_features: Vec<CString>,
23
24    /// The contains pointers to the strings in `clap_features`.
25    clap_features_ptrs: Vec<*const c_char>,
26    /// We only support a single plugin per descriptor right now, so we'll fill in the plugin
27    /// descriptor upfront. We also need to initialize the `CString` fields above first before we
28    /// can initialize this plugin descriptor.
29    plugin_descriptor: Option<clap_plugin_descriptor>,
30}
31
32unsafe impl Send for PluginDescriptor {}
33unsafe impl Sync for PluginDescriptor {}
34
35impl PluginDescriptor {
36    /// Construct the plugin descriptor for a specific CLAP plugin.
37    pub fn for_plugin<P: ClapPlugin>() -> Self {
38        let mut descriptor = Self {
39            clap_id: CString::new(P::CLAP_ID).expect("`CLAP_ID` contained null bytes"),
40            name: CString::new(P::NAME).expect("`NAME` contained null bytes"),
41            vendor: CString::new(P::VENDOR).expect("`VENDOR` contained null bytes"),
42            url: CString::new(P::URL).expect("`URL` contained null bytes"),
43            version: CString::new(P::VERSION).expect("`VERSION` contained null bytes"),
44            clap_manual_url: P::CLAP_MANUAL_URL
45                .map(|url| CString::new(url).expect("`CLAP_MANUAL_URL` contained null bytes")),
46            clap_support_url: P::CLAP_SUPPORT_URL
47                .map(|url| CString::new(url).expect("`CLAP_SUPPORT_URL` contained null bytes")),
48            clap_description: P::CLAP_DESCRIPTION.map(|description| {
49                CString::new(description).expect("`CLAP_DESCRIPTION` contained null bytes")
50            }),
51            clap_features: P::CLAP_FEATURES
52                .iter()
53                .map(|feat| feat.as_str())
54                .map(|s| CString::new(s).expect("`CLAP_FEATURES` contained null bytes"))
55                .collect(),
56
57            // These need to be initialized later as they contain pointers to the fields in this
58            // descriptor
59            clap_features_ptrs: Vec::new(),
60            plugin_descriptor: None,
61        };
62
63        // The keyword list is an environ-like list of char pointers terminated by a null pointer.
64        descriptor.clap_features_ptrs = descriptor
65            .clap_features
66            .iter()
67            .map(|feature| feature.as_ptr())
68            .collect();
69        descriptor.clap_features_ptrs.push(std::ptr::null());
70
71        // We couldn't initialize this directly because of all the CStrings
72        // NOTE: This is safe without pinning this struct because all of the data is already stored
73        //       on the heap
74        descriptor.plugin_descriptor = Some(clap_plugin_descriptor {
75            clap_version: CLAP_VERSION,
76            id: descriptor.clap_id.as_ptr(),
77            name: descriptor.name.as_ptr(),
78            vendor: descriptor.vendor.as_ptr(),
79            url: descriptor.url.as_ptr(),
80            version: descriptor.version.as_ptr(),
81            manual_url: descriptor
82                .clap_manual_url
83                .as_ref()
84                .map(|url| url.as_ptr())
85                .unwrap_or(std::ptr::null()),
86            support_url: descriptor
87                .clap_support_url
88                .as_ref()
89                .map(|url| url.as_ptr())
90                .unwrap_or(std::ptr::null()),
91            description: descriptor
92                .clap_description
93                .as_ref()
94                .map(|description| description.as_ptr())
95                .unwrap_or(std::ptr::null()),
96            features: descriptor.clap_features_ptrs.as_ptr(),
97        });
98
99        descriptor
100    }
101
102    pub fn clap_plugin_descriptor(&self) -> &clap_plugin_descriptor {
103        self.plugin_descriptor.as_ref().unwrap()
104    }
105
106    pub fn clap_id(&self) -> &CStr {
107        self.clap_id.as_c_str()
108    }
109}