Skip to content

Commit 8061b5a

Browse files
committed
Added ExtensionInterface to replace usage of bare dyn Any
1 parent e373adf commit 8061b5a

File tree

5 files changed

+268
-235
lines changed

5 files changed

+268
-235
lines changed

atom/src/port.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ impl PortType for AtomPort {
114114

115115
#[inline]
116116
unsafe fn input_from_raw(pointer: NonNull<c_void>, _sample_count: u32) -> PortReader<'static> {
117-
let header = AtomHeader::from_raw(pointer.cast().as_ref());
117+
let header = AtomHeader::from_raw(&*pointer.cast().as_ptr());
118118
PortReader::new(header.assume_full_atom())
119119
}
120120

121121
#[inline]
122122
unsafe fn output_from_raw(pointer: NonNull<c_void>, _sample_count: u32) -> PortWriter<'static> {
123-
let header = AtomHeader::from_raw_mut(pointer.cast().as_mut());
123+
let header = AtomHeader::from_raw_mut(&mut *pointer.cast().as_ptr());
124124
PortWriter::new(header.assume_full_atom_mut().body_mut())
125125
}
126126
}

core/src/extension.rs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//! This is a complete example on how to create an extension and implement it for a plugin:
1010
//!
1111
//! ```
12-
//! use lv2_core::extension::ExtensionDescriptor;
12+
//! use lv2_core::extension::{ExtensionDescriptor, ExtensionInterface};
1313
//! use lv2_core::prelude::*;
1414
//! use urid::*;
1515
//! use std::any::Any;
@@ -83,7 +83,7 @@
8383
//! self.internal += 1;
8484
//! }
8585
//!
86-
//! fn extension_data(uri: &Uri) -> Option<&'static dyn Any> {
86+
//! fn extension_data(uri: &Uri) -> Option<ExtensionInterface> {
8787
//! // This macro use matches the given URI with the URIs of the given extension descriptors.
8888
//! // If one of them matches, it's interface is returned.
8989
//! //
@@ -118,7 +118,6 @@
118118
//!
119119
//! assert_eq!(42, plugin.internal);
120120
//! ```
121-
use std::any::Any;
122121
use urid::UriBound;
123122

124123
/// A descriptor for a plugin extension.
@@ -127,11 +126,30 @@ use urid::UriBound;
127126
///
128127
/// [For a usage example, see the module documentation.](index.html)
129128
pub trait ExtensionDescriptor: UriBound {
130-
type ExtensionInterface: 'static + Any;
129+
type ExtensionInterface: 'static;
131130

132131
const INTERFACE: &'static Self::ExtensionInterface;
133132
}
134133

134+
#[derive(Copy, Clone)]
135+
pub struct ExtensionInterface {
136+
interface: *const c_void,
137+
}
138+
139+
impl ExtensionInterface {
140+
#[inline]
141+
pub fn new_for<T: ExtensionDescriptor>() -> Self {
142+
Self {
143+
interface: T::INTERFACE as *const _ as *const c_void,
144+
}
145+
}
146+
147+
#[inline]
148+
pub fn get_ptr(self) -> *const c_void {
149+
self.interface
150+
}
151+
}
152+
135153
/// Generate the body of a plugin's `extension_data` function.
136154
///
137155
/// This macro takes a URI as it's first argument, followed by a list of extension descriptors. This will
@@ -143,13 +161,20 @@ pub trait ExtensionDescriptor: UriBound {
143161
#[macro_export]
144162
macro_rules! match_extensions {
145163
($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,
164+
{
165+
extern crate lv2_core as _lv2_core;
166+
//extern crate urid as _urid;
167+
168+
todo!()
169+
/*match ($uri).to_bytes_with_nul() {
170+
$(
171+
<$descriptor as _urid::UriBound>::URI => Some(_lv2_core::extension::ExtensionInterface::new_for::<$descriptor>()),
172+
)*
173+
_ => None,
174+
}*/
151175
}
152176
};
153177
}
154178

155179
pub use crate::match_extensions;
180+
use std::ffi::c_void;

core/src/plugin/instance.rs

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
use crate::extension::ExtensionInterface;
2+
use crate::feature::*;
3+
use crate::plugin::{Plugin, PluginInfo};
4+
use crate::port::PortCollection;
5+
use crate::port::*;
6+
use crate::prelude::LV2_Descriptor;
7+
use std::ffi::c_void;
8+
use std::os::raw::c_char;
9+
use sys::LV2_Handle;
10+
use urid::Uri;
11+
12+
/// Plugin wrapper which translated between the host and the plugin.
13+
///
14+
/// The host interacts with the plugin via a C API, but the plugin is implemented with ideomatic, safe Rust. To bridge this gap, this wrapper is used to translate and abstract the communcation between the host and the plugin.
15+
///
16+
/// This struct is `repr(C)` and has the plugin as it's first field. Therefore, a valid `*mut PluginInstance<T>` is also a valid `*mut T`.
17+
#[repr(C)]
18+
pub struct PluginInstance<T: Plugin> {
19+
/// The plugin instance.
20+
instance: T,
21+
/// A temporary storage for all ports of the plugin.
22+
connections: <T::Ports as PortCollection>::Cache,
23+
/// All features that may be used in the initialization threading class.
24+
init_features: T::InitFeatures,
25+
/// All features that may be used in the audio threading class.
26+
audio_features: T::AudioFeatures,
27+
}
28+
29+
impl<T: Plugin> PluginInstance<T> {
30+
/// Try to create a port collection from the currently collected connections.
31+
///
32+
/// # Safety
33+
///
34+
/// This method is unsafe since it needs to dereference raw pointers, which are only valid if the method is called in the "Audio" threading class.
35+
pub unsafe fn ports(&self, sample_count: u32) -> Option<T::Ports> {
36+
<T::Ports as PortCollection>::from_connections(&self.connections, sample_count)
37+
}
38+
39+
/// Instantiate the plugin.
40+
///
41+
/// This method provides a required method for the C interface of a plugin and is used by the `lv2_descriptors` macro.
42+
///
43+
/// # Safety
44+
///
45+
/// This method is unsafe since it derefences multiple raw pointers and is part of the C interface.
46+
pub unsafe extern "C" fn instantiate(
47+
descriptor: *const sys::LV2_Descriptor,
48+
sample_rate: f64,
49+
bundle_path: *const c_char,
50+
features: *const *const sys::LV2_Feature,
51+
) -> LV2_Handle {
52+
// Dereference the descriptor.
53+
let descriptor = match descriptor.as_ref() {
54+
Some(descriptor) => descriptor,
55+
None => {
56+
eprintln!("Failed to initialize plugin: Descriptor points to null");
57+
return std::ptr::null_mut();
58+
}
59+
};
60+
61+
// Dereference the plugin info.
62+
let plugin_info = match PluginInfo::from_raw(descriptor, bundle_path, sample_rate) {
63+
Ok(info) => info,
64+
Err(e) => {
65+
eprintln!(
66+
"Failed to initialize plugin: Illegal info from host: {:?}",
67+
e
68+
);
69+
return std::ptr::null_mut();
70+
}
71+
};
72+
73+
// Collect the supported features.
74+
let mut init_features_cache = FeatureCache::from_raw(features);
75+
let mut audio_features_cache = init_features_cache.clone();
76+
77+
let mut init_features = match T::InitFeatures::from_cache(
78+
&mut init_features_cache,
79+
ThreadingClass::Instantiation,
80+
) {
81+
Ok(f) => f,
82+
Err(e) => {
83+
eprintln!("{}", e);
84+
return std::ptr::null_mut();
85+
}
86+
};
87+
let audio_features =
88+
match T::AudioFeatures::from_cache(&mut audio_features_cache, ThreadingClass::Audio) {
89+
Ok(f) => f,
90+
Err(e) => {
91+
eprintln!("{}", e);
92+
return std::ptr::null_mut();
93+
}
94+
};
95+
96+
// Instantiate the plugin.
97+
match T::new(&plugin_info, &mut init_features) {
98+
Some(instance) => {
99+
let instance = Box::new(Self {
100+
instance,
101+
connections: <<T::Ports as PortCollection>::Cache as Default>::default(),
102+
init_features,
103+
audio_features,
104+
});
105+
Box::leak(instance) as *mut Self as LV2_Handle
106+
}
107+
None => std::ptr::null_mut(),
108+
}
109+
}
110+
111+
/// Clean the plugin.
112+
///
113+
/// This method provides a required method for the C interface of a plugin and is used by the `lv2_descriptors` macro.
114+
///
115+
/// # Safety
116+
///
117+
/// This method is unsafe since it derefences multiple raw pointers and is part of the C interface.
118+
pub unsafe extern "C" fn cleanup(instance: *mut c_void) {
119+
let instance = instance as *mut Self;
120+
Box::from_raw(instance);
121+
}
122+
123+
/// Call `activate`.
124+
///
125+
/// This method provides a required method for the C interface of a plugin and is used by the `lv2_descriptors` macro.
126+
///
127+
/// # Safety
128+
///
129+
/// This method is unsafe since it derefences multiple raw pointers and is part of the C interface.
130+
pub unsafe extern "C" fn activate(instance: *mut c_void) {
131+
let instance = &mut *(instance as *mut Self);
132+
instance.instance.activate(&mut instance.init_features)
133+
}
134+
135+
/// Call `deactivate`.
136+
///
137+
/// This method provides a required method for the C interface of a plugin and is used by the `lv2_descriptors` macro.
138+
///
139+
/// # Safety
140+
///
141+
/// This method is unsafe since it derefences multiple raw pointers and is part of the C interface.
142+
pub unsafe extern "C" fn deactivate(instance: *mut c_void) {
143+
let instance = &mut *(instance as *mut Self);
144+
instance.instance.deactivate(&mut instance.init_features)
145+
}
146+
147+
/// Update a port pointer.
148+
///
149+
/// This method provides a required method for the C interface of a plugin and is used by the `lv2_descriptors` macro.
150+
///
151+
/// # Safety
152+
///
153+
/// This method is unsafe since it derefences multiple raw pointers and is part of the C interface.
154+
pub unsafe extern "C" fn connect_port(instance: *mut c_void, port: u32, data: *mut c_void) {
155+
let instance = instance as *mut Self;
156+
(*instance).connections.connect(port, data)
157+
}
158+
159+
/// Construct a port collection and call the `run` method.
160+
///
161+
/// This method provides a required method for the C interface of a plugin and is used by the `lv2_descriptors` macro.
162+
///
163+
/// # Safety
164+
///
165+
/// This method is unsafe since it derefences multiple raw pointers and is part of the C interface.
166+
pub unsafe extern "C" fn run(instance: *mut c_void, sample_count: u32) {
167+
let instance = &mut *(instance as *mut Self);
168+
if let Some(mut ports) = instance.ports(sample_count) {
169+
instance
170+
.instance
171+
.run(&mut ports, &mut instance.audio_features, sample_count);
172+
}
173+
}
174+
175+
/// Dereference the URI, call the `extension_data` function and return the pointer.
176+
///
177+
/// This method provides a required method for the C interface of a plugin and is used by the `lv2_descriptors` macro.
178+
///
179+
/// # Safety
180+
///
181+
/// This method is unsafe since it derefences multiple raw pointers and is part of the C interface.
182+
pub unsafe extern "C" fn extension_data(uri: *const c_char) -> *const c_void {
183+
let uri = Uri::from_ptr(uri);
184+
185+
T::extension_data(uri)
186+
.map(ExtensionInterface::get_ptr)
187+
.unwrap_or_else(core::ptr::null)
188+
}
189+
190+
/// Retrieve the internal plugin.
191+
pub fn plugin_handle(&mut self) -> &mut T {
192+
&mut self.instance
193+
}
194+
195+
/// Retrieve the required handles to execute an Initialization class method.
196+
///
197+
/// This method can be used by extensions to call an extension method in the Initialization threading class and provide it the host features for that class.
198+
pub fn init_class_handle(&mut self) -> (&mut T, &mut T::InitFeatures) {
199+
(&mut self.instance, &mut self.init_features)
200+
}
201+
202+
/// Retrieve the required handles to execute an Audio class method.
203+
///
204+
/// This method can be used by extensions to call an extension method in the Audio threading class and provide it the host features for that class.
205+
pub fn audio_class_handle(&mut self) -> (&mut T, &mut T::AudioFeatures) {
206+
(&mut self.instance, &mut self.audio_features)
207+
}
208+
}
209+
210+
#[doc(hidden)]
211+
pub unsafe trait PluginInstanceDescriptor {
212+
const DESCRIPTOR: sys::LV2_Descriptor;
213+
}
214+
215+
unsafe impl<T: Plugin> PluginInstanceDescriptor for T {
216+
const DESCRIPTOR: LV2_Descriptor = LV2_Descriptor {
217+
URI: T::URI.as_ptr() as *const u8 as *const ::std::os::raw::c_char,
218+
instantiate: Some(PluginInstance::<T>::instantiate),
219+
connect_port: Some(PluginInstance::<T>::connect_port),
220+
activate: Some(PluginInstance::<T>::activate),
221+
run: Some(PluginInstance::<T>::run),
222+
deactivate: Some(PluginInstance::<T>::deactivate),
223+
cleanup: Some(PluginInstance::<T>::cleanup),
224+
extension_data: Some(PluginInstance::<T>::extension_data),
225+
};
226+
}

0 commit comments

Comments
 (0)