lv2_core/extension.rs
1//! Means to extend the interface of a plugin.
2//!
3//! This module is relatively thin: It only contains a trait and a macro. Instead, most of the extension handling is a convention:
4//!
5//! An extension is a trait a plugin can implement and every extension has a descriptor: This is a marker struct that implements the [`ExtensionDescriptor`](trait.ExtensionDescriptor.html) trait for every plugin that implements the extension. This descriptor is then used by the [`match_extensions`](../macro.match_extensions.html) macro to generate the body of a plugin's `extension_data` method.
6//!
7//! # Example
8//!
9//! This is a complete example on how to create an extension and implement it for a plugin:
10//!
11//! ```
12//! use lv2_core::extension::ExtensionDescriptor;
13//! use lv2_core::prelude::*;
14//! use urid::*;
15//! use std::any::Any;
16//! use std::ffi::c_void;
17//! use std::marker::PhantomData;
18//! use std::path::Path;
19//!
20//! // ######################
21//! // Defining the extension
22//! // ######################
23//!
24//! /// The trait that actually extends the plugin.
25//! pub trait MyExtension: Plugin {
26//! fn add_number(&mut self, number: u32);
27//! }
28//!
29//! /// A descriptor for the plugin. This is just a marker type to associate constants and methods with.
30//! pub struct MyExtensionDescriptor<P: MyExtension> {
31//! plugin: PhantomData<P>,
32//! }
33//!
34//! #[repr(C)]
35//! /// This struct would be part of a sys crate.
36//! pub struct MyExtensionInterface {
37//! add_number: unsafe extern "C" fn(*mut c_void, number: u32),
38//! }
39//!
40//! unsafe impl<P: MyExtension> UriBound for MyExtensionDescriptor<P> {
41//! const URI: &'static [u8] = b"urn:my-project:my-extension\0";
42//! }
43//!
44//! impl<P: MyExtension> MyExtensionDescriptor<P> {
45//! /// The extern, unsafe version of the extending method.
46//! ///
47//! /// This is actually called by the host.
48//! unsafe extern "C" fn extern_add_number(handle: *mut c_void, number: u32) {
49//! let plugin = (handle as *mut P).as_mut().unwrap();
50//! plugin.add_number(number);
51//! }
52//! }
53//!
54//! // Implementing the trait that contains the interface.
55//! impl<P: MyExtension> ExtensionDescriptor for MyExtensionDescriptor<P> {
56//! type ExtensionInterface = MyExtensionInterface;
57//!
58//! const INTERFACE: &'static MyExtensionInterface = &MyExtensionInterface {
59//! add_number: Self::extern_add_number,
60//! };
61//! }
62//!
63//! // ##########
64//! // The plugin
65//! // ##########
66//!
67//! /// This plugin actually isn't a plugin, it only has a counter.
68//! #[uri("urn:my-project:my-plugin")]
69//! pub struct MyPlugin {
70//! internal: u32,
71//! }
72//!
73//! impl Plugin for MyPlugin {
74//! type Ports = ();
75//! type InitFeatures = ();
76//! type AudioFeatures = ();
77//!
78//! fn new(_: &PluginInfo, _: &mut ()) -> Option<Self> {
79//! Some(Self { internal: 0 })
80//! }
81//!
82//! fn run(&mut self, _: &mut (), _: &mut (), _: u32) {
83//! self.internal += 1;
84//! }
85//!
86//! fn extension_data(uri: &Uri) -> Option<&'static dyn Any> {
87//! // This macro use matches the given URI with the URIs of the given extension descriptors.
88//! // If one of them matches, it's interface is returned.
89//! //
90//! // Note that you have to add the type parameter. Otherwise, bad things may happen!
91//! match_extensions![uri, MyExtensionDescriptor<Self>]
92//! }
93//! }
94//!
95//! // Actually implementing the extension.
96//! impl MyExtension for MyPlugin {
97//! fn add_number(&mut self, number: u32) {
98//! self.internal += number;
99//! }
100//! }
101//!
102//! // ########
103//! // The host
104//! // ########
105//!
106//! let plugin_uri: &Uri = MyPlugin::uri();
107//! let bundle_path = Path::new("");
108//! let sample_rate = 44100.0;
109//! let plugin_info = PluginInfo::new(plugin_uri, bundle_path, sample_rate);
110//!
111//! let mut plugin = MyPlugin::new(&plugin_info, &mut ()).unwrap();
112//!
113//! let extension = MyPlugin::extension_data(MyExtensionDescriptor::<MyPlugin>::uri())
114//! .and_then(|interface| interface.downcast_ref::<MyExtensionInterface>())
115//! .unwrap();
116//!
117//! unsafe { (extension.add_number)(&mut plugin as *mut _ as *mut c_void, 42) };
118//!
119//! assert_eq!(42, plugin.internal);
120//! ```
121use std::any::Any;
122use urid::UriBound;
123
124/// A descriptor for a plugin extension.
125///
126/// This trait is very minimal: It only contains a constant, static reference to the extension interface.
127///
128/// [For a usage example, see the module documentation.](index.html)
129pub trait ExtensionDescriptor: UriBound {
130 type ExtensionInterface: 'static + Any;
131
132 const INTERFACE: &'static Self::ExtensionInterface;
133}
134
135/// Generate the body of a plugin's `extension_data` function.
136///
137/// This macro takes a URI as it's first argument, followed by a list of extension descriptors. This will
138/// create a match expression that matches the given URI with the URIs of the extension descriptors. If one of the extension URIs matches, the statement returns the interface of the descriptor.
139///
140/// The generated statement returns a value of `Option<&'static dyn std::any::Any>`.
141///
142/// See the documentation of the `extension` module for more information on how to use this macro.
143#[macro_export]
144macro_rules! match_extensions {
145 ($uri:expr, $($descriptor:ty),*) => {
146 match ($uri).to_bytes_with_nul() {
147 $(
148 <$descriptor as UriBound>::URI => Some(<$descriptor as ExtensionDescriptor>::INTERFACE as &'static dyn ::std::any::Any),
149 )*
150 _ => None,
151 }
152 };
153}
154
155pub use crate::match_extensions;