diff --git a/common/src/events/io/implementation.rs b/common/src/events/io/implementation.rs index 9401b154..21fa7eea 100644 --- a/common/src/events/io/implementation.rs +++ b/common/src/events/io/implementation.rs @@ -143,6 +143,18 @@ unsafe extern "C" fn void_push( true } +impl InputEventBuffer for () { + #[inline] + fn len(&self) -> u32 { + 0 + } + + #[inline] + fn get(&self, _index: u32) -> Option<&UnknownEvent> { + None + } +} + impl InputEventBuffer for T { #[inline] fn len(&self) -> u32 { diff --git a/extensions/src/ambisonic/host.rs b/extensions/src/ambisonic/host.rs index b78d2651..5a489eea 100644 --- a/extensions/src/ambisonic/host.rs +++ b/extensions/src/ambisonic/host.rs @@ -13,7 +13,7 @@ impl PluginAmbisonic { /// Check if the plugin supports the given ambisonic configuration. pub fn is_config_supported( &self, - handle: &mut PluginMainThreadHandle, + handle: &PluginMainThreadHandle, config: AmbisonicConfig, ) -> bool { if let Some(is_config_supported) = handle.use_extension(&self.0).is_config_supported { @@ -27,7 +27,7 @@ impl PluginAmbisonic { /// Get the ambisonic configuration for the given port, if applicable. pub fn get_config( &self, - handle: &mut PluginMainThreadHandle, + handle: &PluginMainThreadHandle, is_input: bool, port_index: u32, ) -> Option { @@ -53,7 +53,7 @@ pub trait HostAmbisonicImpl { /// Notify the host that the ambisonic configuration for one or more ports has changed. /// /// The info can only change when the plugin is de-activated. - fn changed(&mut self); + fn changed(&self); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -73,8 +73,8 @@ where for<'a> H: HostHandlers: HostAmbisonicImpl>, { unsafe { - HostWrapper::::handle(host, |host| { - host.main_thread().as_mut().changed(); + HostWrapper::::handle_main_thread(host, |host| { + host.changed(); Ok(()) }); } diff --git a/extensions/src/ambisonic/plugin.rs b/extensions/src/ambisonic/plugin.rs index 5fbcade3..6494a1e0 100644 --- a/extensions/src/ambisonic/plugin.rs +++ b/extensions/src/ambisonic/plugin.rs @@ -10,7 +10,7 @@ impl HostAmbisonic { /// Notify the host that the ambisonic configuration for one or more ports has changed. /// /// The info can only change when the plugin is de-activated. - pub fn changed(&self, handle: &mut HostMainThreadHandle) { + pub fn changed(&self, handle: &HostMainThreadHandle) { if let Some(changed) = handle.use_extension(&self.0).changed { // SAFETY: This type ensures the function pointer is valid. unsafe { (changed)(handle.as_raw()) } diff --git a/extensions/src/audio_ports/host.rs b/extensions/src/audio_ports/host.rs index fc53a6da..a9286173 100644 --- a/extensions/src/audio_ports/host.rs +++ b/extensions/src/audio_ports/host.rs @@ -38,7 +38,7 @@ impl AudioPortInfoBuffer { impl PluginAudioPorts { /// Returns number of audio ports, for either input or output - pub fn count(&self, plugin: &mut PluginMainThreadHandle, is_input: bool) -> u32 { + pub fn count(&self, plugin: &PluginMainThreadHandle, is_input: bool) -> u32 { match plugin.use_extension(&self.0).count { None => 0, // SAFETY: This type ensures the function pointer is valid. @@ -49,7 +49,7 @@ impl PluginAudioPorts { /// Gets information about an audio port by its index, for either input or output. pub fn get<'b>( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, index: u32, is_input: bool, buffer: &'b mut AudioPortInfoBuffer, @@ -76,7 +76,7 @@ pub trait HostAudioPortsImpl { /// Rescan the full list of audio ports according to the flags. /// It is illegal to ask the host to rescan with a flag that is not supported (see [`is_rescan_flag_supported`](Self::is_rescan_flag_supported)). /// Certain flags require the plugin to be de-activated. - fn rescan(&mut self, flags: AudioPortRescanFlags); + fn rescan(&self, flags: AudioPortRescanFlags); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -96,11 +96,8 @@ unsafe extern "C" fn is_rescan_flag_supported(host: *const clap_host, flag: u where H: for<'a> HostHandlers: HostAudioPortsImpl>, { - HostWrapper::::handle(host, |host| { - Ok(host - .main_thread() - .as_ref() - .is_rescan_flag_supported(AudioPortRescanFlags::from_bits_truncate(flag))) + HostWrapper::::handle_main_thread(host, |host| { + Ok(host.is_rescan_flag_supported(AudioPortRescanFlags::from_bits_truncate(flag))) }) .unwrap_or(false) } @@ -110,10 +107,8 @@ unsafe extern "C" fn rescan(host: *const clap_host, flags: u32) where H: for<'a> HostHandlers: HostAudioPortsImpl>, { - HostWrapper::::handle(host, |host| { - host.main_thread() - .as_mut() - .rescan(AudioPortRescanFlags::from_bits_truncate(flags)); + HostWrapper::::handle_main_thread(host, |host| { + host.rescan(AudioPortRescanFlags::from_bits_truncate(flags)); Ok(()) }); diff --git a/extensions/src/audio_ports/plugin.rs b/extensions/src/audio_ports/plugin.rs index 33f7bf2e..044922d3 100644 --- a/extensions/src/audio_ports/plugin.rs +++ b/extensions/src/audio_ports/plugin.rs @@ -178,7 +178,7 @@ impl HostAudioPorts { /// It is illegal to ask the host to rescan with a flag that is not supported (see [`is_rescan_flag_supported`](Self::is_rescan_flag_supported)). /// Certain flags require the plugin to be de-activated. #[inline] - pub fn rescan(&self, host: &mut HostMainThreadHandle, flags: AudioPortRescanFlags) { + pub fn rescan(&self, host: &HostMainThreadHandle, flags: AudioPortRescanFlags) { if let Some(rescan) = host.use_extension(&self.0).rescan { // SAFETY: This type ensures the function pointer is valid. unsafe { rescan(host.as_raw(), flags.bits()) } diff --git a/extensions/src/audio_ports_activation.rs b/extensions/src/audio_ports_activation.rs index 86824fc9..8ad597ec 100644 --- a/extensions/src/audio_ports_activation.rs +++ b/extensions/src/audio_ports_activation.rs @@ -90,7 +90,7 @@ mod host { impl PluginAudioPortsActivation { /// Returns true if the plugin supports calling [`set_active_audio_active`](Self::set_active_audio_active). #[inline] - pub fn can_activate_while_processing(&self, plugin: &mut PluginMainThreadHandle) -> bool { + pub fn can_activate_while_processing(&self, plugin: &PluginMainThreadHandle) -> bool { match plugin.use_extension(&self.0).can_activate_while_processing { None => false, Some(can_activate_while_processing) => { diff --git a/extensions/src/audio_ports_config/host.rs b/extensions/src/audio_ports_config/host.rs index a8db9a67..679a1449 100644 --- a/extensions/src/audio_ports_config/host.rs +++ b/extensions/src/audio_ports_config/host.rs @@ -29,7 +29,7 @@ impl AudioPortsConfigBuffer { impl PluginAudioPortsConfig { /// Returns the number of available [`AudioPortsConfiguration`]s. - pub fn count(&self, plugin: &mut PluginMainThreadHandle) -> u32 { + pub fn count(&self, plugin: &PluginMainThreadHandle) -> u32 { match plugin.use_extension(&self.0).count { None => 0, // SAFETY: This type ensures the function pointer is valid. @@ -43,7 +43,7 @@ impl PluginAudioPortsConfig { /// unnecessary allocations. pub fn get<'b>( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, index: u32, buffer: &'b mut AudioPortsConfigBuffer, ) -> Option> { @@ -71,7 +71,7 @@ impl PluginAudioPortsConfig { #[inline] pub fn select( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, configuration_id: ClapId, ) -> Result<(), AudioPortConfigSelectError> { // SAFETY: This type ensures the function pointer is valid. @@ -94,7 +94,7 @@ impl PluginAudioPortsConfig { impl PluginAudioPortsConfigInfo { /// Gets the id of the currently selected config, or [`None`] if the current port /// layout isn't part of the config list. - pub fn current_config(&self, plugin: &mut PluginMainThreadHandle) -> Option { + pub fn current_config(&self, plugin: &PluginMainThreadHandle) -> Option { // SAFETY: This type ensures the function pointer is valid. let id = unsafe { plugin.use_extension(&self.0).current_config?(plugin.as_raw()) }; if id == CLAP_INVALID_ID { @@ -108,7 +108,7 @@ impl PluginAudioPortsConfigInfo { /// This is analogous to [`PluginAudioPorts::get`](crate::audio_ports::PluginAudioPorts::get). pub fn get<'b>( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, config_id: ClapId, index: u32, is_input: bool, @@ -140,7 +140,7 @@ impl PluginAudioPortsConfigInfo { pub trait HostAudioPortsConfigImpl { /// Informs the host that the available Audio Ports Configuration list has changed and needs to /// be rescanned. - fn rescan(&mut self); + fn rescan(&self); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -160,8 +160,8 @@ unsafe extern "C" fn rescan(host: *const clap_host) where H: for<'a> HostHandlers: HostAudioPortsConfigImpl>, { - HostWrapper::::handle(host, |host| { - host.main_thread().as_mut().rescan(); + HostWrapper::::handle_main_thread(host, |host| { + host.rescan(); Ok(()) }); diff --git a/extensions/src/audio_ports_config/plugin.rs b/extensions/src/audio_ports_config/plugin.rs index 4552c60e..1168a78a 100644 --- a/extensions/src/audio_ports_config/plugin.rs +++ b/extensions/src/audio_ports_config/plugin.rs @@ -238,7 +238,7 @@ impl HostAudioPortsConfig { /// Informs the host that the available Audio Ports Configuration list has changed and needs to /// be rescanned. #[inline] - pub fn rescan(&self, host: &mut HostMainThreadHandle) { + pub fn rescan(&self, host: &HostMainThreadHandle) { if let Some(rescan) = host.use_extension(&self.0).rescan { // SAFETY: This type ensures the function pointer is valid. unsafe { rescan(host.as_raw()) } diff --git a/extensions/src/clap_wrapper/vst3/host.rs b/extensions/src/clap_wrapper/vst3/host.rs index f84700eb..1a65aa57 100644 --- a/extensions/src/clap_wrapper/vst3/host.rs +++ b/extensions/src/clap_wrapper/vst3/host.rs @@ -27,7 +27,7 @@ impl PluginAsVST3 { #[inline] pub fn get_num_midi_channels( &self, - plugin: &mut PluginMainThreadHandle<'_>, + plugin: &PluginMainThreadHandle<'_>, note_port: u32, ) -> u32 { let Some(ext) = plugin.use_extension(&self.0).get_num_midi_channels else { @@ -42,7 +42,7 @@ impl PluginAsVST3 { #[inline] pub fn supported_note_expressions( &self, - plugin: &mut PluginMainThreadHandle<'_>, + plugin: &PluginMainThreadHandle<'_>, ) -> SupportedNoteExpressions { let Some(ext) = plugin.use_extension(&self.0).supported_note_expressions else { return SupportedNoteExpressions::empty(); diff --git a/extensions/src/context_menu/host.rs b/extensions/src/context_menu/host.rs index e4d13d10..ed61f80d 100644 --- a/extensions/src/context_menu/host.rs +++ b/extensions/src/context_menu/host.rs @@ -8,7 +8,7 @@ impl PluginContextMenu { #[inline] pub fn populate( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, target: ContextMenuTarget, builder: &mut ContextMenuBuilder, ) -> Result<(), ContextMenuError> { @@ -36,7 +36,7 @@ impl PluginContextMenu { #[inline] pub fn perform( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, target: ContextMenuTarget, action_id: ClapId, ) -> Result<(), ContextMenuError> { @@ -63,7 +63,7 @@ pub trait HostContextMenuImpl { /// Asks the host to populate the given `builder`, with the contents of a context menu /// that targets the given `target`. fn populate( - &mut self, + &self, target: ContextMenuTarget, builder: &mut ContextMenuBuilder, ) -> Result<(), HostError>; @@ -72,14 +72,14 @@ pub trait HostContextMenuImpl { /// /// The given `action_id` belongs to the menu created by [`populate`](Self::populate) with the /// given `target`. - fn perform(&mut self, target: ContextMenuTarget, action_id: ClapId) -> Result<(), HostError>; + fn perform(&self, target: ContextMenuTarget, action_id: ClapId) -> Result<(), HostError>; /// Returns `true` if the host can pop up its context menu on behalf of the plugin, `false` otherwise. - fn can_popup(&mut self) -> bool; + fn can_popup(&self) -> bool; /// Asks the host to pop up its context menu at a given location. fn popup( - &mut self, + &self, target: ContextMenuTarget, screen_index: i32, x: i32, @@ -110,7 +110,7 @@ unsafe extern "C" fn populate( where H: for<'a> HostHandlers: HostContextMenuImpl>, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { // SAFETY: The CLAP spec requires this pointer to be either NULL or valid for reads. let target = unsafe { ContextMenuTarget::from_raw_ptr(target) }; @@ -118,7 +118,7 @@ where // for the duration of this function call, which is the (inferred) lifetime we give it here. let mut builder = unsafe { ContextMenuBuilder::from_raw(builder) }; - host.main_thread().as_mut().populate(target, &mut builder)?; + host.populate(target, &mut builder)?; Ok(()) }) @@ -134,14 +134,14 @@ unsafe extern "C" fn perform( where H: for<'a> HostHandlers: HostContextMenuImpl>, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { // SAFETY: The CLAP spec requires this pointer to be either NULL or valid for reads. let target = unsafe { ContextMenuTarget::from_raw_ptr(target) }; let action_id = ClapId::from_raw(action_id) .ok_or(HostWrapperError::InvalidParameter("Invalid Action ID"))?; - host.main_thread().as_mut().perform(target, action_id)?; + host.perform(target, action_id)?; Ok(()) }) .is_some() @@ -152,8 +152,7 @@ unsafe extern "C" fn can_popup(host: *const clap_host) -> bool where H: for<'a> HostHandlers: HostContextMenuImpl>, { - HostWrapper::::handle(host, |host| Ok(host.main_thread().as_mut().can_popup())) - .unwrap_or(false) + HostWrapper::::handle_main_thread(host, |host| Ok(host.can_popup())).unwrap_or(false) } #[allow(clippy::missing_safety_doc)] @@ -167,12 +166,11 @@ unsafe extern "C" fn popup( where H: for<'a> HostHandlers: HostContextMenuImpl>, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { // SAFETY: The CLAP spec requires this pointer to be either NULL or valid for reads. let target = unsafe { ContextMenuTarget::from_raw_ptr(target) }; - host.main_thread() - .as_mut() - .popup(target, screen_index, x, y)?; + host.popup(target, screen_index, x, y)?; + Ok(()) }) .is_some() diff --git a/extensions/src/context_menu/plugin.rs b/extensions/src/context_menu/plugin.rs index 55dd09d0..49da8a7f 100644 --- a/extensions/src/context_menu/plugin.rs +++ b/extensions/src/context_menu/plugin.rs @@ -8,7 +8,7 @@ impl HostContextMenu { #[inline] pub fn populate( &self, - host: &mut HostMainThreadHandle, + host: &HostMainThreadHandle, target: ContextMenuTarget, builder: &mut ContextMenuBuilder, ) -> Result<(), ContextMenuError> { @@ -36,7 +36,7 @@ impl HostContextMenu { #[inline] pub fn perform( &self, - host: &mut HostMainThreadHandle, + host: &HostMainThreadHandle, target: ContextMenuTarget, action_id: ClapId, ) -> Result<(), ContextMenuError> { @@ -59,7 +59,7 @@ impl HostContextMenu { /// Returns `true` if the host can pop up its context menu on behalf of the plugin, `false` otherwise. #[inline] - pub fn can_popup(&self, host: &mut HostMainThreadHandle) -> bool { + pub fn can_popup(&self, host: &HostMainThreadHandle) -> bool { let Some(can_popup) = host.use_extension(&self.0).can_popup else { return false; }; @@ -73,7 +73,7 @@ impl HostContextMenu { #[inline] pub fn popup( &self, - host: &mut HostMainThreadHandle, + host: &HostMainThreadHandle, target: ContextMenuTarget, screen_index: i32, x: i32, diff --git a/extensions/src/event_registry.rs b/extensions/src/event_registry.rs index d189638d..eb62212f 100644 --- a/extensions/src/event_registry.rs +++ b/extensions/src/event_registry.rs @@ -97,10 +97,10 @@ mod host { where H: for<'a> HostHandlers: HostEventRegistryImpl>, { - let result = HostWrapper::::handle(host, |host| { + let result = HostWrapper::::handle_main_thread(host, |host| { let space_name = CStr::from_ptr(space_name); - let result = host.main_thread().as_ref().query(space_name); + let result = host.query(space_name); *space_id = EventSpaceId::optional_id(&result); Ok(result.is_some()) diff --git a/extensions/src/gui/host.rs b/extensions/src/gui/host.rs index dbbfbab0..48fa6b6a 100644 --- a/extensions/src/gui/host.rs +++ b/extensions/src/gui/host.rs @@ -5,7 +5,7 @@ impl PluginGui { /// Indicate whether a particular API is supported. pub fn is_api_supported( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, configuration: GuiConfiguration, ) -> bool { match plugin.use_extension(&self.0).is_api_supported { @@ -26,7 +26,7 @@ impl PluginGui { /// situate the plugin in floating or embedded state despite having called this. pub fn get_preferred_api( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, ) -> Option> { let mut api_type = core::ptr::null(); let mut is_floating = true; @@ -60,7 +60,7 @@ impl PluginGui { /// If `is_floating` is false, the plugin must embed its window in the parent (host). pub fn create( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, configuration: GuiConfiguration, ) -> Result<(), GuiError> { // SAFETY: This type ensures the function pointer is valid. @@ -82,7 +82,7 @@ impl PluginGui { } /// Free all resources associated with the GUI - pub fn destroy(&self, plugin: &mut PluginMainThreadHandle) { + pub fn destroy(&self, plugin: &PluginMainThreadHandle) { if let Some(destroy) = plugin.use_extension(&self.0).destroy { // SAFETY: This type ensures the function pointer is valid. unsafe { destroy(plugin.as_raw()) } @@ -93,11 +93,7 @@ impl PluginGui { /// /// Overrides OS settings, and should not be used if the windowing API uses logical pixels. Can /// be ignored if the plugin will query the OS directly and perform its own calculations. - pub fn set_scale( - &self, - plugin: &mut PluginMainThreadHandle, - scale: f64, - ) -> Result<(), GuiError> { + pub fn set_scale(&self, plugin: &PluginMainThreadHandle, scale: f64) -> Result<(), GuiError> { let success = // SAFETY: This type ensures the function pointer is valid. unsafe { plugin.use_extension(&self.0).set_scale.ok_or(GuiError::CreateError)?(plugin.as_raw(), scale) }; @@ -109,7 +105,7 @@ impl PluginGui { } /// Get current size of GUI - pub fn get_size(&self, plugin: &mut PluginMainThreadHandle) -> Option { + pub fn get_size(&self, plugin: &PluginMainThreadHandle) -> Option { let mut width = 0; let mut height = 0; @@ -128,7 +124,7 @@ impl PluginGui { /// Tell host if GUI can be resized /// /// Only applies to embedded windows. - pub fn can_resize(&self, plugin: &mut PluginMainThreadHandle) -> bool { + pub fn can_resize(&self, plugin: &PluginMainThreadHandle) -> bool { if let Some(can_resize) = plugin.use_extension(&self.0).can_resize { // SAFETY: This type ensures the function pointer is valid. unsafe { can_resize(plugin.as_raw()) } @@ -138,7 +134,7 @@ impl PluginGui { } /// Provide hints on the resize-ability of the GUI - pub fn get_resize_hints(&self, plugin: &mut PluginMainThreadHandle) -> Option { + pub fn get_resize_hints(&self, plugin: &PluginMainThreadHandle) -> Option { let mut hints = clap_gui_resize_hints { aspect_ratio_height: u32::MAX, aspect_ratio_width: u32::MAX, @@ -165,11 +161,7 @@ impl PluginGui { /// /// Only applies if the GUI is resizable and embedded in a parent window. Must return /// dimensions smaller than or equal to the requested dimensions. - pub fn adjust_size( - &self, - plugin: &mut PluginMainThreadHandle, - size: GuiSize, - ) -> Option { + pub fn adjust_size(&self, plugin: &PluginMainThreadHandle, size: GuiSize) -> Option { let mut new_size = size; // SAFETY: This type ensures the function pointer is valid. @@ -184,11 +176,7 @@ impl PluginGui { } /// Set the size of an embedded window - pub fn set_size( - &self, - plugin: &mut PluginMainThreadHandle, - size: GuiSize, - ) -> Result<(), GuiError> { + pub fn set_size(&self, plugin: &PluginMainThreadHandle, size: GuiSize) -> Result<(), GuiError> { // SAFETY: This type ensures the function pointer is valid. let success = unsafe { plugin @@ -212,7 +200,7 @@ impl PluginGui { /// is called. pub unsafe fn set_parent( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, window: Window, ) -> Result<(), GuiError> { // SAFETY: This type ensures the function pointer is valid. @@ -240,7 +228,7 @@ impl PluginGui { /// is called. pub unsafe fn set_transient( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, window: Window, ) -> Result<(), GuiError> { // SAFETY: This type ensures the function pointer is valid. @@ -257,7 +245,7 @@ impl PluginGui { /// Give a suggested window title to the plugin. /// /// Only applies to floating windows. - pub fn suggest_title(&self, plugin: &mut PluginMainThreadHandle, title: &CStr) { + pub fn suggest_title(&self, plugin: &PluginMainThreadHandle, title: &CStr) { if let Some(suggest_title) = plugin.use_extension(&self.0).suggest_title { // SAFETY: This type ensures the function pointer is valid. unsafe { suggest_title(plugin.as_raw(), title.as_ptr()) } @@ -265,7 +253,7 @@ impl PluginGui { } /// Show the window - pub fn show(&self, plugin: &mut PluginMainThreadHandle) -> Result<(), GuiError> { + pub fn show(&self, plugin: &PluginMainThreadHandle) -> Result<(), GuiError> { // SAFETY: This type ensures the function pointer is valid. unsafe { plugin @@ -280,7 +268,7 @@ impl PluginGui { /// Hide the window /// /// This should not free the resources associated with the GUI, just hide it. - pub fn hide(&self, plugin: &mut PluginMainThreadHandle) -> Result<(), GuiError> { + pub fn hide(&self, plugin: &PluginMainThreadHandle) -> Result<(), GuiError> { // SAFETY: This type ensures the function pointer is valid. unsafe { plugin diff --git a/extensions/src/latency.rs b/extensions/src/latency.rs index 147d5072..0a029dd1 100644 --- a/extensions/src/latency.rs +++ b/extensions/src/latency.rs @@ -48,7 +48,7 @@ mod host { impl PluginLatency { /// Returns the plugin latency in samples. #[inline] - pub fn get(&self, plugin: &mut PluginMainThreadHandle) -> u32 { + pub fn get(&self, plugin: &PluginMainThreadHandle) -> u32 { match plugin.use_extension(&self.0).get { None => 0, // SAFETY: This type ensures the function pointer is valid. @@ -60,7 +60,7 @@ mod host { /// Implementation of the Host-side of the Latency extension. pub trait HostLatencyImpl { /// The plugin latency has changed and should be re-queried. - fn changed(&mut self); + fn changed(&self); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -79,8 +79,8 @@ mod host { where for<'a> H: HostHandlers: HostLatencyImpl>, { - HostWrapper::::handle(host, |host| { - host.main_thread().as_mut().changed(); + HostWrapper::::handle_main_thread(host, |host| { + host.changed(); Ok(()) }); } @@ -99,7 +99,7 @@ mod plugin { /// The latency is allowed to change only during the [`PluginAudioProcessor::activate`](clack_plugin::plugin::PluginAudioProcessor::activate) callback. /// If the plugin is active, you should request a restart first. #[inline] - pub fn changed(&self, host: &mut HostMainThreadHandle) { + pub fn changed(&self, host: &HostMainThreadHandle) { if let Some(changed) = host.use_extension(&self.0).changed { // SAFETY: This type ensures the function pointer is valid. unsafe { changed(host.as_raw()) } diff --git a/extensions/src/note_name/host.rs b/extensions/src/note_name/host.rs index aae0004d..2163c54c 100644 --- a/extensions/src/note_name/host.rs +++ b/extensions/src/note_name/host.rs @@ -27,7 +27,7 @@ impl NoteNameBuffer { impl PluginNoteName { /// Returns the number of available [`NoteName`]s. - pub fn count(&self, plugin: &mut PluginMainThreadHandle) -> usize { + pub fn count(&self, plugin: &PluginMainThreadHandle) -> usize { match plugin.use_extension(&self.0).count { None => 0, // SAFETY: This type ensures the function pointer is valid. @@ -41,7 +41,7 @@ impl PluginNoteName { /// unnecessary allocations. pub fn get<'b>( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, index: u32, buffer: &'b mut NoteNameBuffer, ) -> Option> { @@ -62,7 +62,7 @@ impl PluginNoteName { pub trait HostNoteNameImpl { /// Informs the host that the available Note Names list has changed and needs to /// be rescanned. - fn changed(&mut self); + fn changed(&self); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -82,8 +82,8 @@ unsafe extern "C" fn changed(host: *const clap_host) where for<'h> H: HostHandlers: HostNoteNameImpl>, { - HostWrapper::::handle(host, |host| { - host.main_thread().as_mut().changed(); + HostWrapper::::handle_main_thread(host, |host| { + host.changed(); Ok(()) }); diff --git a/extensions/src/note_name/plugin.rs b/extensions/src/note_name/plugin.rs index e024f230..37704a43 100644 --- a/extensions/src/note_name/plugin.rs +++ b/extensions/src/note_name/plugin.rs @@ -100,7 +100,7 @@ impl HostNoteName { /// Informs the host that the available Note Name list has changed and needs to /// be rescanned. #[inline] - pub fn changed(&self, host: &mut HostMainThreadHandle) { + pub fn changed(&self, host: &HostMainThreadHandle) { if let Some(changed) = host.use_extension(&self.0).changed { // SAFETY: This type ensures the function pointer is valid. unsafe { changed(host.as_raw()) } diff --git a/extensions/src/note_ports/host.rs b/extensions/src/note_ports/host.rs index 8df6660a..2e0e5174 100644 --- a/extensions/src/note_ports/host.rs +++ b/extensions/src/note_ports/host.rs @@ -27,7 +27,7 @@ impl NotePortInfoBuffer { impl PluginNotePorts { /// Returns number of note ports, for either input or output. - pub fn count(&self, plugin: &mut PluginMainThreadHandle, is_input: bool) -> u32 { + pub fn count(&self, plugin: &PluginMainThreadHandle, is_input: bool) -> u32 { match plugin.use_extension(&self.0).count { None => 0, // SAFETY: This type ensures the function pointer is valid. @@ -38,7 +38,7 @@ impl PluginNotePorts { /// Get information about a note port by its index, for either input or output. pub fn get<'b>( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, index: u32, is_input: bool, buffer: &'b mut NotePortInfoBuffer, @@ -63,7 +63,7 @@ pub trait HostNotePortsImpl { /// Rescan the full list of note ports according to the flags. /// See [`NotePortRescanFlags`] for more details. - fn rescan(&mut self, flags: NotePortRescanFlags); + fn rescan(&self, flags: NotePortRescanFlags); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -83,10 +83,8 @@ unsafe extern "C" fn supported_dialects(host: *const clap_host) -> u32 where for<'h> H: HostHandlers: HostNotePortsImpl>, { - HostWrapper::::handle(host, |host| { - Ok(host.main_thread().as_ref().supported_dialects().bits()) - }) - .unwrap_or(0) + HostWrapper::::handle_main_thread(host, |host| Ok(host.supported_dialects().bits())) + .unwrap_or(0) } #[allow(clippy::missing_safety_doc)] @@ -94,10 +92,8 @@ unsafe extern "C" fn rescan(host: *const clap_host, flags: u32) where for<'h> H: HostHandlers: HostNotePortsImpl>, { - HostWrapper::::handle(host, |host| { - host.main_thread() - .as_mut() - .rescan(NotePortRescanFlags::from_bits_truncate(flags)); + HostWrapper::::handle_main_thread(host, |host| { + host.rescan(NotePortRescanFlags::from_bits_truncate(flags)); Ok(()) }); diff --git a/extensions/src/note_ports/plugin.rs b/extensions/src/note_ports/plugin.rs index 1843ab60..c4d9edd3 100644 --- a/extensions/src/note_ports/plugin.rs +++ b/extensions/src/note_ports/plugin.rs @@ -114,7 +114,7 @@ impl HostNotePorts { /// Rescan the full list of note ports according to the flags. /// See [`NotePortRescanFlags`] for more details. #[inline] - pub fn rescan(&self, host: &mut HostMainThreadHandle, flags: NotePortRescanFlags) { + pub fn rescan(&self, host: &HostMainThreadHandle, flags: NotePortRescanFlags) { if let Some(rescan) = host.use_extension(&self.0).rescan { // SAFETY: This type ensures the function pointer is valid. unsafe { rescan(host.as_raw(), flags.bits()) } diff --git a/extensions/src/param_indication.rs b/extensions/src/param_indication.rs index 1bebbac4..d4b87bbf 100644 --- a/extensions/src/param_indication.rs +++ b/extensions/src/param_indication.rs @@ -105,7 +105,7 @@ mod host { #[inline] pub fn set_mapping( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, param_id: ClapId, has_mapping: bool, color: Option, @@ -140,7 +140,7 @@ mod host { #[inline] pub fn set_automation( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, param_id: ClapId, automation_state: ParamIndicationAutomation, color: Option, diff --git a/extensions/src/params/host.rs b/extensions/src/params/host.rs index 6fb0d80c..83de6ecc 100644 --- a/extensions/src/params/host.rs +++ b/extensions/src/params/host.rs @@ -28,7 +28,7 @@ impl ParamInfoBuffer { impl PluginParams { /// Returns the total number of parameters the plugin exposes. - pub fn count(&self, plugin: &mut PluginMainThreadHandle) -> u32 { + pub fn count(&self, plugin: &PluginMainThreadHandle) -> u32 { match plugin.use_extension(&self.0).count { None => 0, // SAFETY: This type ensures the function pointer is valid. @@ -53,7 +53,7 @@ impl PluginParams { /// Returns `true` on success, or `false` if `index` is out of bounds. pub fn get_info<'b>( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, index: u32, buffer: &'b mut ParamInfoBuffer, ) -> Option> { @@ -86,7 +86,7 @@ impl PluginParams { /// # Return /// /// Returns the current value of the parameter, or `None` if the ID is invalid. - pub fn get_value(&self, plugin: &mut PluginMainThreadHandle, param_id: ClapId) -> Option { + pub fn get_value(&self, plugin: &PluginMainThreadHandle, param_id: ClapId) -> Option { let mut value = 0.0; // SAFETY: This type ensures the function pointer is valid. let valid = unsafe { @@ -116,7 +116,7 @@ impl PluginParams { /// Returns `Ok(())` on success, or `Err` if formatting fails. pub fn value_to_text<'b>( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, param_id: ClapId, value: f64, buffer: &'b mut [u8], @@ -162,7 +162,7 @@ impl PluginParams { /// Returns the parsed value, or `None` if parsing fails or the ID is invalid. pub fn text_to_value( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, param_id: ClapId, text: &CStr, ) -> Option { @@ -262,10 +262,10 @@ pub trait HostParamsImplShared { pub trait HostParamsImplMainThread { /// Rescan the full list of parameters, according to the given `flags`. /// See [`ParamRescanFlags`] for more details. - fn rescan(&mut self, flags: ParamRescanFlags); + fn rescan(&self, flags: ParamRescanFlags); /// Clears references (such as automation or modulation) to a parameter (identified by `param_id`), according to the given `flags`. /// See [`ParamClearFlags`] for more details. - fn clear(&mut self, param_id: ClapId, flags: ParamClearFlags); + fn clear(&self, param_id: ClapId, flags: ParamClearFlags); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -287,10 +287,8 @@ unsafe extern "C" fn rescan(host: *const clap_host, flags: clap_param_rescan_ where for<'a> H: HostHandlers: HostParamsImplMainThread>, { - HostWrapper::::handle(host, |host| { - host.main_thread() - .as_mut() - .rescan(ParamRescanFlags::from_bits_truncate(flags)); + HostWrapper::::handle_main_thread(host, |host| { + host.rescan(ParamRescanFlags::from_bits_truncate(flags)); Ok(()) }); @@ -301,12 +299,11 @@ unsafe extern "C" fn clear(host: *const clap_host, param_id: u32, flags: clap where for<'a> H: HostHandlers: HostParamsImplMainThread>, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { let param_id = ClapId::from_raw(param_id) .ok_or(HostWrapperError::InvalidParameter("Invalid param_id"))?; - host.main_thread() - .as_mut() - .clear(param_id, ParamClearFlags::from_bits_truncate(flags)); + + host.clear(param_id, ParamClearFlags::from_bits_truncate(flags)); Ok(()) }); diff --git a/extensions/src/params/plugin.rs b/extensions/src/params/plugin.rs index 390ba8d1..b2e0d4bd 100644 --- a/extensions/src/params/plugin.rs +++ b/extensions/src/params/plugin.rs @@ -375,7 +375,7 @@ impl HostParams { /// /// See [`ParamRescanFlags`] for more details. #[inline] - pub fn rescan(&self, host: &mut HostMainThreadHandle, flags: ParamRescanFlags) { + pub fn rescan(&self, host: &HostMainThreadHandle, flags: ParamRescanFlags) { if let Some(rescan) = host.use_extension(&self.0).rescan { // SAFETY: This type ensures the function pointer is valid. unsafe { rescan(host.as_raw(), flags.bits()) } @@ -386,7 +386,7 @@ impl HostParams { /// /// See [`ParamClearFlags`] for more details. #[inline] - pub fn clear(&self, host: &mut HostMainThreadHandle, param_id: ClapId, flags: ParamClearFlags) { + pub fn clear(&self, host: &HostMainThreadHandle, param_id: ClapId, flags: ParamClearFlags) { if let Some(clear) = host.use_extension(&self.0).clear { // SAFETY: This type ensures the function pointer is valid. unsafe { clear(host.as_raw(), param_id.get(), flags.bits()) } diff --git a/extensions/src/posix_fd.rs b/extensions/src/posix_fd.rs index 39fbcdf3..e71fb5be 100644 --- a/extensions/src/posix_fd.rs +++ b/extensions/src/posix_fd.rs @@ -98,7 +98,7 @@ mod host { /// Note this callback is "level-triggered". It means that for instance, a writable File /// Descriptor will continuously produce "on_fd()" events. #[inline] - pub fn on_fd(&self, plugin: &mut PluginMainThreadHandle, fd: RawFd, flags: FdFlags) { + pub fn on_fd(&self, plugin: &PluginMainThreadHandle, fd: RawFd, flags: FdFlags) { if let Some(on_fd) = plugin.use_extension(&self.0).on_fd { // SAFETY: This type ensures the function pointer is valid. unsafe { on_fd(plugin.as_raw(), fd, flags.bits()) } @@ -112,11 +112,11 @@ mod host { /// /// The host will call the plugin's `on_fd` method every time the File Descriptor fires one /// of these events. - fn register_fd(&mut self, fd: RawFd, flags: FdFlags) -> Result<(), HostError>; + fn register_fd(&self, fd: RawFd, flags: FdFlags) -> Result<(), HostError>; /// Updates the set of events a given File Descriptor will fire. - fn modify_fd(&mut self, fd: RawFd, flags: FdFlags) -> Result<(), HostError>; + fn modify_fd(&self, fd: RawFd, flags: FdFlags) -> Result<(), HostError>; /// Removes a given File Descriptor from the host's event reactor. - fn unregister_fd(&mut self, fd: RawFd) -> Result<(), HostError>; + fn unregister_fd(&self, fd: RawFd) -> Result<(), HostError>; } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -142,10 +142,8 @@ mod host { where for<'a> ::MainThread<'a>: HostPosixFdImpl, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { Ok(host - .main_thread() - .as_mut() .register_fd(fd, FdFlags::from_bits_truncate(flags)) .is_ok()) }) @@ -161,10 +159,8 @@ mod host { where for<'a> ::MainThread<'a>: HostPosixFdImpl, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { Ok(host - .main_thread() - .as_mut() .modify_fd(fd, FdFlags::from_bits_truncate(flags)) .is_ok()) }) @@ -175,10 +171,8 @@ mod host { where for<'a> ::MainThread<'a>: HostPosixFdImpl, { - HostWrapper::::handle(host, |host| { - Ok(host.main_thread().as_mut().unregister_fd(fd).is_ok()) - }) - .unwrap_or(false) + HostWrapper::::handle_main_thread(host, |host| Ok(host.unregister_fd(fd).is_ok())) + .unwrap_or(false) } } @@ -197,7 +191,7 @@ mod plugin { /// of these events. pub fn register_fd( &self, - host: &mut HostMainThreadHandle, + host: &HostMainThreadHandle, fd: RawFd, flags: FdFlags, ) -> Result<(), FdError> { @@ -217,7 +211,7 @@ mod plugin { /// Updates the set of events a given File Descriptor will fire. pub fn modify_fd( &self, - host: &mut HostMainThreadHandle, + host: &HostMainThreadHandle, fd: RawFd, flags: FdFlags, ) -> Result<(), FdError> { @@ -235,11 +229,7 @@ mod plugin { } /// Removes a given File Descriptor from the host's event reactor. - pub fn unregister_fd( - &self, - host: &mut HostMainThreadHandle, - fd: RawFd, - ) -> Result<(), FdError> { + pub fn unregister_fd(&self, host: &HostMainThreadHandle, fd: RawFd) -> Result<(), FdError> { let unregister_fd = host .use_extension(&self.0) .unregister_fd diff --git a/extensions/src/preset_discovery/host/extension.rs b/extensions/src/preset_discovery/host/extension.rs index 63688a0e..19c1297d 100644 --- a/extensions/src/preset_discovery/host/extension.rs +++ b/extensions/src/preset_discovery/host/extension.rs @@ -24,7 +24,7 @@ impl PluginPresetLoad { #[inline] pub fn load_from_location( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, location: Location, load_key: Option<&CStr>, ) -> Result<(), PresetLoadError> { @@ -70,7 +70,7 @@ pub trait HostPresetLoadImpl { /// `error_code` is the operating system error, as returned by e.g. [`std::io::Error::raw_os_error`], if applicable. /// If not applicable, it should be set to a non-error value, e.g. 0 on Unix and Windows. fn on_error( - &mut self, + &self, location: Location, load_key: Option<&CStr>, os_error: i32, @@ -80,7 +80,7 @@ pub trait HostPresetLoadImpl { /// Informs the host that a given preset has been loaded. /// /// This can be used to e.g. keep the host preset browser in sync with the plugin's. - fn loaded(&mut self, location: Location, load_key: Option<&CStr>); + fn loaded(&self, location: Location, load_key: Option<&CStr>); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -104,15 +104,14 @@ unsafe extern "C" fn loaded( ) where for<'a> H: HostHandlers: HostPresetLoadImpl>, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { // SAFETY: path is guaranteed to be either NULL or valid by the CLAP spec. let location = unsafe { Location::from_raw(kind, path) } .ok_or(HostWrapperError::InvalidParameter("Invalid location"))?; // SAFETY: load_key is guaranteed to be either NULL or valid by the CLAP spec. let load_key = unsafe { cstr_from_nullable_ptr(load_key) }; - - host.main_thread().as_mut().loaded(location, load_key); + host.loaded(location, load_key); Ok(()) }); @@ -129,7 +128,7 @@ unsafe extern "C" fn on_error( ) where for<'a> H: HostHandlers: HostPresetLoadImpl>, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { // SAFETY: path is guaranteed to be either NULL or valid by the CLAP spec. let location = unsafe { Location::from_raw(kind, path) } .ok_or(HostWrapperError::InvalidParameter("Invalid location"))?; @@ -138,10 +137,7 @@ unsafe extern "C" fn on_error( let load_key = unsafe { cstr_from_nullable_ptr(load_key) }; // SAFETY: message is guaranteed to be either NULL or valid by the CLAP spec. let message = unsafe { cstr_from_nullable_ptr(message) }; - - host.main_thread() - .as_mut() - .on_error(location, load_key, os_error, message); + host.on_error(location, load_key, os_error, message); Ok(()) }); diff --git a/extensions/src/preset_discovery/plugin/extension.rs b/extensions/src/preset_discovery/plugin/extension.rs index c3ffa4d8..a3f9e681 100644 --- a/extensions/src/preset_discovery/plugin/extension.rs +++ b/extensions/src/preset_discovery/plugin/extension.rs @@ -12,7 +12,7 @@ impl HostPresetLoad { #[inline] pub fn on_error( &self, - host: &mut HostMainThreadHandle, + host: &HostMainThreadHandle, location: Location, load_key: Option<&CStr>, os_error: i32, @@ -38,12 +38,7 @@ impl HostPresetLoad { /// /// This can be used to e.g. keep the host preset browser in sync with the plugin's. #[inline] - pub fn loaded( - &self, - host: &mut HostMainThreadHandle, - location: Location, - load_key: Option<&CStr>, - ) { + pub fn loaded(&self, host: &HostMainThreadHandle, location: Location, load_key: Option<&CStr>) { if let Some(loaded) = host.use_extension(&self.0).loaded { let (kind, path) = location.to_raw(); // SAFETY: Host pointer comes from HostMainThreadHandle, string pointers come from &CStr, so they are all valid. diff --git a/extensions/src/remote_controls.rs b/extensions/src/remote_controls.rs index f7bf62fc..cc0c54a9 100644 --- a/extensions/src/remote_controls.rs +++ b/extensions/src/remote_controls.rs @@ -120,7 +120,7 @@ mod host { impl PluginRemoteControls { /// Returns the number of Remote Control pages the plugin provides. #[inline] - pub fn count(&self, plugin: &mut PluginMainThreadHandle) -> u32 { + pub fn count(&self, plugin: &PluginMainThreadHandle) -> u32 { let Some(count) = plugin.use_extension(&self.0).count else { return 0; }; @@ -138,7 +138,7 @@ mod host { #[inline] pub fn get<'a>( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, index: u32, buffer: &'a mut RemoteControlsPageBuffer, ) -> Option> { @@ -162,10 +162,10 @@ mod host { /// Implementation of the Host-side of the Remote Controls extension. pub trait HostRemoteControlsImpl { /// Informs the host that the Remote Control pages provided by the plugin have changed and need to be re-scanned. - fn changed(&mut self); + fn changed(&self); /// Suggests the host to display/activate a given page, e.g. because it corresponds to what the user /// is currently editing in the plugin's GUI. - fn suggest_page(&mut self, page_id: ClapId); + fn suggest_page(&self, page_id: ClapId); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -185,8 +185,8 @@ mod host { where H: for<'a> HostHandlers: HostRemoteControlsImpl>, { - HostWrapper::::handle(host, |host| { - host.main_thread().as_mut().changed(); + HostWrapper::::handle_main_thread(host, |host| { + host.changed(); Ok(()) }); } @@ -196,11 +196,11 @@ mod host { where H: for<'a> HostHandlers: HostRemoteControlsImpl>, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { let id = ClapId::from_raw(page_id) .ok_or(HostWrapperError::InvalidParameter("Invalid page ID"))?; - host.main_thread().as_mut().suggest_page(id); + host.suggest_page(id); Ok(()) }); } @@ -219,7 +219,7 @@ mod plugin { impl HostRemoteControls { /// Informs the host that the Remote Control pages provided by the plugin have changed and need to be re-scanned. #[inline] - pub fn changed(&self, plugin: &mut HostMainThreadHandle) { + pub fn changed(&self, plugin: &HostMainThreadHandle) { if let Some(changed) = plugin.use_extension(&self.0).changed { // SAFETY: This type guarantees the function pointer is valid, and // HostMainThreadHandle guarantees the host pointer is valid @@ -229,7 +229,7 @@ mod plugin { /// Suggests the host to display/activate a given page, e.g. because it corresponds to what the user /// is currently editing in the plugin's GUI. - pub fn suggest_page(&self, plugin: &mut HostMainThreadHandle, page_id: ClapId) { + pub fn suggest_page(&self, plugin: &HostMainThreadHandle, page_id: ClapId) { if let Some(suggest_page) = plugin.use_extension(&self.0).suggest_page { // SAFETY: This type guarantees the function pointer is valid, and // HostMainThreadHandle guarantees the host pointer is valid diff --git a/extensions/src/render.rs b/extensions/src/render.rs index 370abb24..c2eaa368 100644 --- a/extensions/src/render.rs +++ b/extensions/src/render.rs @@ -155,7 +155,7 @@ mod host { /// This is especially useful for plugins that are acting as a proxy to hardware devices, or /// other real-time events. #[inline] - pub fn has_realtime_requirement(&self, plugin: &mut PluginMainThreadHandle) -> bool { + pub fn has_realtime_requirement(&self, plugin: &PluginMainThreadHandle) -> bool { if let Some(has_hard_realtime_requirement) = plugin.use_extension(&self.0).has_hard_realtime_requirement { @@ -174,7 +174,7 @@ mod host { /// to the given render mode. pub fn set( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, render_mode: RenderMode, ) -> Result<(), PluginRenderError> { // SAFETY: This type ensures the function pointer is valid. diff --git a/extensions/src/state.rs b/extensions/src/state.rs index 4e46677d..17686b3d 100644 --- a/extensions/src/state.rs +++ b/extensions/src/state.rs @@ -17,6 +17,7 @@ //! ``` //! use std::error::Error; //! use std::io::Cursor; +//! use std::cell::Cell; //! use std::sync::OnceLock; //! use clack_extensions::state::{HostState, HostStateImpl, PluginState}; //! use clack_host::prelude::*; @@ -48,27 +49,27 @@ //! //! struct MyHostMainThread<'a> { //! shared: &'a MyHostShared, -//! is_state_dirty: bool +//! is_state_dirty: Cell //! } //! //! impl<'a> MainThreadHandler<'a> for MyHostMainThread<'a> { //! /* ... */ -//! # fn initialized(&mut self, _instance: InitializedPluginHandle<'a>) {} +//! # fn initialized(&self, _instance: InitializedPluginHandle<'a>) {} //! } //! //! // Implement the Host State extension for the plugin to notify us of its dirty save state //! impl<'a> HostStateImpl for MyHostMainThread<'a> { -//! fn mark_dirty(&mut self) { +//! fn mark_dirty(&self) { //! // Notify the user that the plugin should now be saved. //! // For this example, we'll just use a boolean. -//! self.is_state_dirty = true; +//! self.is_state_dirty.set(true); //! } //! } //! //! # pub fn main() -> Result<(), Box> { //! # mod utils { include!("./__doc_utils.rs"); } //! let mut plugin_instance: PluginInstance = /* ... */ -//! # utils::get_working_instance(|_| MyHostShared { state_ext: OnceLock::new() }, |shared| MyHostMainThread { is_state_dirty: false, shared })?; +//! # utils::get_working_instance(|_| MyHostShared { state_ext: OnceLock::new() }, |shared| MyHostMainThread { is_state_dirty: false.into(), shared })?; //! //! let state_ext = plugin_instance.access_shared_handler(|h| h.state_ext.get()) //! .expect("Plugin is not yet instantiated") diff --git a/extensions/src/state/host.rs b/extensions/src/state/host.rs index 86822d8f..385fd3c0 100644 --- a/extensions/src/state/host.rs +++ b/extensions/src/state/host.rs @@ -13,7 +13,7 @@ impl PluginState { /// If this operation fails, a [`StateError`] is returned. pub fn load( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, reader: &mut R, ) -> Result<(), StateError> { let mut stream = InputStream::from_reader(reader); @@ -42,7 +42,7 @@ impl PluginState { /// If this operation fails, a [`StateError`] is returned. pub fn save( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, writer: &mut W, ) -> Result<(), StateError> { let mut stream = OutputStream::from_writer(writer); @@ -68,7 +68,7 @@ pub trait HostStateImpl { /// The plugin state has changed, and may need to be saved again. /// /// Note that if a parameter value changes, it is implicit that the state is dirty. - fn mark_dirty(&mut self); + fn mark_dirty(&self); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -88,8 +88,8 @@ unsafe extern "C" fn mark_dirty(host: *const clap_host) where for<'a> H: HostHandlers: HostStateImpl>, { - HostWrapper::::handle(host, |host| { - host.main_thread().as_mut().mark_dirty(); + HostWrapper::::handle_main_thread(host, |host| { + host.mark_dirty(); Ok(()) }); diff --git a/extensions/src/state_context.rs b/extensions/src/state_context.rs index 27fce4fc..c84333dc 100644 --- a/extensions/src/state_context.rs +++ b/extensions/src/state_context.rs @@ -186,7 +186,7 @@ mod host { /// If this operation fails, a [`StateError`] is returned. pub fn load( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, reader: &mut impl Read, context_type: StateContextType, ) -> Result<(), StateError> { @@ -221,7 +221,7 @@ mod host { /// If this operation fails, a [`StateError`] is returned. pub fn save( &self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, writer: &mut impl Write, context_type: StateContextType, ) -> Result<(), StateError> { diff --git a/extensions/src/surround/host.rs b/extensions/src/surround/host.rs index 8b0a548c..352d040e 100644 --- a/extensions/src/surround/host.rs +++ b/extensions/src/surround/host.rs @@ -10,7 +10,7 @@ impl PluginSurround { /// Check if the plugin supports a given surround configuration mask. pub fn is_channel_mask_supported( &self, - handle: &mut PluginMainThreadHandle, + handle: &PluginMainThreadHandle, mask: SurroundChannels, ) -> bool { match handle.use_extension(&self.0).is_channel_mask_supported { @@ -28,7 +28,7 @@ impl PluginSurround { /// This function should only be called if the port it is called for has `port_type` set to [`AudioPortType::SURROUND`](`crate::audio_ports::AudioPortType::SURROUND`). pub fn get_channel_map<'a>( &self, - handle: &mut PluginMainThreadHandle, + handle: &PluginMainThreadHandle, is_input: bool, port_index: u32, buffer: &'a mut [u8], @@ -62,7 +62,7 @@ pub trait HostSurroundImpl { /// Notify the host that the surround configuration for one or more ports has changed. /// /// The channel map can only change when the plugin is de-activated. - fn changed(&mut self); + fn changed(&self); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -82,8 +82,8 @@ where for<'a> H: HostHandlers: HostSurroundImpl>, { unsafe { - HostWrapper::::handle(host, |host| { - host.main_thread().as_mut().changed(); + HostWrapper::::handle_main_thread(host, |host| { + host.changed(); Ok(()) }); } diff --git a/extensions/src/surround/plugin.rs b/extensions/src/surround/plugin.rs index 6cd36007..7541fdf1 100644 --- a/extensions/src/surround/plugin.rs +++ b/extensions/src/surround/plugin.rs @@ -32,7 +32,7 @@ impl SurroundMapWriter<'_> { impl HostSurround { /// Notify the host that the surround configuration for one or more ports has changed. - pub fn changed(&self, handle: &mut HostMainThreadHandle) { + pub fn changed(&self, handle: &HostMainThreadHandle) { if let Some(changed) = handle.use_extension(&self.0).changed { // SAFETY: This type ensures the function pointer is valid. unsafe { (changed)(handle.as_raw()) } diff --git a/extensions/src/timer.rs b/extensions/src/timer.rs index 77afd3e3..d4d3f894 100644 --- a/extensions/src/timer.rs +++ b/extensions/src/timer.rs @@ -96,7 +96,7 @@ mod plugin { #[inline] pub fn register_timer( &self, - host: &mut HostMainThreadHandle, + host: &HostMainThreadHandle, period_ms: u32, ) -> Result { let mut id = 0u32; @@ -123,7 +123,7 @@ mod plugin { #[inline] pub fn unregister_timer( &self, - host: &mut HostMainThreadHandle, + host: &HostMainThreadHandle, timer_id: TimerId, ) -> Result<(), TimerError> { let unregister_timer = host @@ -192,7 +192,7 @@ mod host { /// # Errors /// /// Returns an error if the host failed or refused to register this timer. - fn register_timer(&mut self, period_ms: u32) -> Result; + fn register_timer(&self, period_ms: u32) -> Result; /// Unregisters a given Timer, identified by its unique [`TimerId`]. /// @@ -202,7 +202,7 @@ mod host { /// # Errors /// /// Returns an error if the host failed to unregister this timer. - fn unregister_timer(&mut self, timer_id: TimerId) -> Result<(), HostError>; + fn unregister_timer(&self, timer_id: TimerId) -> Result<(), HostError>; } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -227,16 +227,14 @@ mod host { where for<'a> H: HostHandlers: HostTimerImpl>, { - HostWrapper::::handle(host, |host| { - match host.main_thread().as_mut().register_timer(period_ms) { - Ok(id) => { - *timer_id = id.0; - Ok(true) - } - Err(_) => { - *timer_id = u32::MAX; - Ok(false) - } + HostWrapper::::handle_main_thread(host, |host| match host.register_timer(period_ms) { + Ok(id) => { + *timer_id = id.0; + Ok(true) + } + Err(_) => { + *timer_id = u32::MAX; + Ok(false) } }) .unwrap_or(false) @@ -247,12 +245,8 @@ mod host { where for<'a> H: HostHandlers: HostTimerImpl>, { - HostWrapper::::handle(host, |host| { - Ok(host - .main_thread() - .as_mut() - .unregister_timer(TimerId(timer_id)) - .is_ok()) + HostWrapper::::handle_main_thread(host, |host| { + Ok(host.unregister_timer(TimerId(timer_id)).is_ok()) }) .unwrap_or(false) } @@ -263,7 +257,7 @@ mod host { /// The callback is also given the unique [`TimerId`] of the timer that ticked and triggered /// it. #[inline] - pub fn on_timer(&self, plugin: &mut PluginMainThreadHandle, timer_id: TimerId) { + pub fn on_timer(&self, plugin: &PluginMainThreadHandle, timer_id: TimerId) { if let Some(on_timer) = plugin.use_extension(&self.0).on_timer { // SAFETY: This type ensures the function pointer is valid. unsafe { on_timer(plugin.as_raw(), timer_id.0) } diff --git a/extensions/src/track_info.rs b/extensions/src/track_info.rs index 13a2ebd2..cc43b07a 100644 --- a/extensions/src/track_info.rs +++ b/extensions/src/track_info.rs @@ -363,7 +363,7 @@ mod host { impl PluginTrackInfo { /// Notifies the plugin that its current track's info has changed. - pub fn changed(&self, plugin: &mut PluginMainThreadHandle) { + pub fn changed(&self, plugin: &PluginMainThreadHandle) { if let Some(changed) = plugin.use_extension(&self.0).changed { // SAFETY: This type guarantees the function pointer is valid, and // PluginMainThreadHandle guarantees the plugin pointer is valid @@ -448,7 +448,7 @@ mod host { /// Implementation of the Host-side of the Track Info extension. pub trait HostTrackInfoImpl { /// Gets info about the track the plugin belongs to. - fn get<'a>(&'a mut self, writer: &mut TrackInfoWriter<'_, 'a>); + fn get<'a>(&'a self, writer: &mut TrackInfoWriter<'_, 'a>); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -467,9 +467,9 @@ mod host { where H: for<'a> HostHandlers: HostTrackInfoImpl>, { - HostWrapper::::handle(host, |host| { + HostWrapper::::handle_main_thread(host, |host| { let mut writer = TrackInfoWriter::from_raw(buf); - host.main_thread().as_mut().get(&mut writer); + host.get(&mut writer); Ok(writer.is_set) }) .unwrap_or(false) diff --git a/extensions/src/voice_info.rs b/extensions/src/voice_info.rs index 1cbeecf1..a99de29a 100644 --- a/extensions/src/voice_info.rs +++ b/extensions/src/voice_info.rs @@ -102,7 +102,7 @@ mod host { /// Retrieves a plugin's Voice Information. /// /// If the plugin failed to provide any Voice Information, this returns [`None`]. - pub fn get(&self, plugin: &mut PluginMainThreadHandle) -> Option { + pub fn get(&self, plugin: &PluginMainThreadHandle) -> Option { let info = MaybeUninit::zeroed(); // SAFETY: This type ensures the function pointer is valid. @@ -119,7 +119,7 @@ mod host { pub trait HostVoiceInfoImpl { /// Indicates the plugin has changed its voice configuration, and the host needs to update /// it by calling [`get`](PluginVoiceInfo::get) again. - fn changed(&mut self); + fn changed(&self); } // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -138,8 +138,8 @@ mod host { where H: for<'a> HostHandlers: HostVoiceInfoImpl>, { - HostWrapper::::handle(host, |host| { - host.main_thread().as_mut().changed(); + HostWrapper::::handle_main_thread(host, |host| { + host.changed(); Ok(()) }); } @@ -156,7 +156,7 @@ mod plugin { impl HostVoiceInfo { /// Indicates the plugin has changed its voice configuration, and the host needs to update /// it by calling [`get`](PluginVoiceInfoImpl::get) again. - pub fn changed(&self, host: &mut HostMainThreadHandle) { + pub fn changed(&self, host: &HostMainThreadHandle) { if let Some(changed) = host.use_extension(&self.0).changed { // SAFETY: This type ensures the function pointer is valid. unsafe { changed(host.as_raw()) } diff --git a/host/examples/cpal/src/host.rs b/host/examples/cpal/src/host.rs index 4643fb41..2969f4ad 100644 --- a/host/examples/cpal/src/host.rs +++ b/host/examples/cpal/src/host.rs @@ -1,4 +1,5 @@ use crate::discovery::FoundPlugin; +use std::cell::{Cell, OnceCell}; use clack_extensions::audio_ports::{AudioPortRescanFlags, HostAudioPortsImpl, PluginAudioPorts}; use clack_extensions::gui::{GuiSize, HostGui, PluginGui}; @@ -116,15 +117,15 @@ pub struct CpalHostMainThread<'a> { /// (this is unused in this example, but this is kept here for demonstration purposes). _shared: &'a CpalHostShared, /// A handle to the plugin instance. - plugin: Option>, + plugin: OnceCell>, /// A handle to the plugin's Timer extension, if it supports it. /// This is placed here, since only the main thread will ever use that extension. - timer_support: Option, + timer_support: Cell>, /// The timer implementation. timers: Rc, /// A handle to the plugin's GUI extension, if it supports it. - gui: Option, + gui: Cell>, } impl<'a> CpalHostMainThread<'a> { @@ -132,20 +133,20 @@ impl<'a> CpalHostMainThread<'a> { fn new(shared: &'a CpalHostShared) -> Self { Self { _shared: shared, - plugin: None, - timer_support: None, - gui: None, + plugin: OnceCell::new(), + timer_support: None.into(), + gui: None.into(), timers: Rc::new(Timers::new()), } } } impl<'a> MainThreadHandler<'a> for CpalHostMainThread<'a> { - fn initialized(&mut self, instance: InitializedPluginHandle<'a>) { - self.gui = instance.get_extension(); - self.timer_support = instance.get_extension(); + fn initialized(&self, instance: InitializedPluginHandle<'a>) { + self.gui.set(instance.get_extension()); + self.timer_support.set(instance.get_extension()); - self.plugin = Some(instance); + self.plugin.set(instance).unwrap(); } } @@ -174,8 +175,8 @@ pub fn run(plugin: FoundPlugin) -> Result<(), Box> { let _stream = activate_to_stream(&mut instance)?; let gui = instance - .access_handler(|h| h.gui) - .map(|gui| Gui::new(gui, &mut instance.plugin_handle())); + .access_handler(|h| h.gui.get()) + .map(|gui| Gui::new(gui, &instance.plugin_handle())); let gui = gui.and_then(|gui| Some((gui.needs_floating()?, gui))); @@ -200,7 +201,7 @@ fn run_gui_floating( mut gui: Gui, ) -> Result<(), Box> { println!("Opening GUI in floating mode"); - gui.open_floating(&mut instance.plugin_handle())?; + gui.open_floating(&instance.plugin_handle())?; for message in receiver { match message { @@ -213,7 +214,7 @@ fn run_gui_floating( } } - gui.destroy(&mut instance.plugin_handle()); + gui.destroy(&instance.plugin_handle()); Ok(()) } @@ -230,11 +231,12 @@ fn run_gui_embedded( let event_loop = EventLoop::new()?; - let mut window = Some(gui.open_embedded(&mut instance.plugin_handle(), &event_loop)?); + let mut window = Some(gui.open_embedded(&instance.plugin_handle(), &event_loop)?); let uses_logical_pixels = gui.configuration.unwrap().api_type.uses_logical_size(); - let timers = instance.access_handler(|h| h.timer_support.map(|ext| (h.timers.clone(), ext))); + let timers = + instance.access_handler(|h| h.timer_support.get().map(|ext| (h.timers.clone(), ext))); #[allow(deprecated)] event_loop.run(move |event, target| { @@ -266,7 +268,7 @@ fn run_gui_embedded( Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested => { println!("Plugin window closed, stopping."); - gui.destroy(&mut instance.plugin_handle()); + gui.destroy(&instance.plugin_handle()); window.take(); // Drop the window return; } @@ -278,7 +280,7 @@ fn run_gui_embedded( let window = window.as_ref().unwrap(); let scale_factor = window.scale_factor(); - let actual_size = gui.resize(&mut instance.plugin_handle(), size, scale_factor); + let actual_size = gui.resize(&instance.plugin_handle(), size, scale_factor); if actual_size != size.into() { let _ = window.request_inner_size(actual_size); @@ -287,13 +289,13 @@ fn run_gui_embedded( _ => {} }, Event::LoopExiting => { - gui.destroy(&mut instance.plugin_handle()); + gui.destroy(&instance.plugin_handle()); } _ => {} } let wait_duration = if let Some((timers, timer_ext)) = &timers { - timers.tick_timers(timer_ext, &mut instance.plugin_handle()); + timers.tick_timers(timer_ext, &instance.plugin_handle()); timers .smallest_duration() @@ -358,7 +360,7 @@ impl HostAudioPortsImpl for CpalHostMainThread<'_> { false } - fn rescan(&mut self, _flags: AudioPortRescanFlags) { + fn rescan(&self, _flags: AudioPortRescanFlags) { // We don't support audio ports changing on the fly } } @@ -368,17 +370,17 @@ impl HostNotePortsImpl for CpalHostMainThread<'_> { NoteDialects::CLAP } - fn rescan(&mut self, _flags: NotePortRescanFlags) { + fn rescan(&self, _flags: NotePortRescanFlags) { // We don't support note ports changing on the fly } } impl HostParamsImplMainThread for CpalHostMainThread<'_> { - fn rescan(&mut self, _flags: ParamRescanFlags) { + fn rescan(&self, _flags: ParamRescanFlags) { // We don't track param values at all } - fn clear(&mut self, _param_id: ClapId, _flags: ParamClearFlags) {} + fn clear(&self, _param_id: ClapId, _flags: ParamClearFlags) {} } impl HostParamsImplShared for CpalHostShared { diff --git a/host/examples/cpal/src/host/audio/midi.rs b/host/examples/cpal/src/host/audio/midi.rs index 10a7a484..7907de7d 100644 --- a/host/examples/cpal/src/host/audio/midi.rs +++ b/host/examples/cpal/src/host/audio/midi.rs @@ -216,18 +216,16 @@ fn push_midi_to_buffer( /// /// This returns `None` if it couldn't find one. fn find_main_note_port_index(instance: &mut PluginInstance) -> Option<(u16, bool)> { - let mut handle = instance.plugin_handle(); + let handle = instance.plugin_handle(); let plugin_note_ports = handle.get_extension::()?; let mut buffer = NotePortInfoBuffer::new(); // Only count up to u16::MAX, since port indexes in events only support u16 - let ports_count = plugin_note_ports - .count(&mut handle, true) - .min(u16::MAX as u32); + let ports_count = plugin_note_ports.count(&handle, true).min(u16::MAX as u32); for i in 0..ports_count { - let Some(port_info) = plugin_note_ports.get(&mut handle, i, true, &mut buffer) else { + let Some(port_info) = plugin_note_ports.get(&handle, i, true, &mut buffer) else { continue; }; diff --git a/host/examples/cpal/src/host/gui.rs b/host/examples/cpal/src/host/gui.rs index 6f5895bb..972df022 100644 --- a/host/examples/cpal/src/host/gui.rs +++ b/host/examples/cpal/src/host/gui.rs @@ -49,7 +49,7 @@ pub struct Gui { impl Gui { /// Initializes the GUI state for a given instance - pub fn new(plugin_gui: PluginGui, instance: &mut PluginMainThreadHandle) -> Self { + pub fn new(plugin_gui: PluginGui, instance: &PluginMainThreadHandle) -> Self { Self { plugin_gui, configuration: Self::negotiate_configuration(&plugin_gui, instance), @@ -64,7 +64,7 @@ impl Gui { /// only figures out if that is okay for the plugin, and whether is supports embedding. fn negotiate_configuration( gui: &PluginGui, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, ) -> Option> { // This implementation only supports the default: Win32 on Windows, Cocoa on macOS, X11 on Unix // We completely ignore the plugin's preference here: it's platform-default or nothing. @@ -118,7 +118,7 @@ impl Gui { } /// Opens the plugin's GUI in floating mode. - pub fn open_floating(&mut self, plugin: &mut PluginMainThreadHandle) -> Result<(), GuiError> { + pub fn open_floating(&mut self, plugin: &PluginMainThreadHandle) -> Result<(), GuiError> { let Some(configuration) = self.configuration else { panic!("Called open_floating on incompatible plugin") }; @@ -137,7 +137,7 @@ impl Gui { #[allow(unsafe_code)] pub fn open_embedded( &mut self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, event_loop: &EventLoop<()>, ) -> Result> { let gui = self.plugin_gui; @@ -182,7 +182,7 @@ impl Gui { /// The scale factor is also given in case the API uses logical pixel (Cocoa on macOS). pub fn resize( &mut self, - plugin: &mut PluginMainThreadHandle, + plugin: &PluginMainThreadHandle, size: PhysicalSize, scale_factor: f64, ) -> Size { @@ -214,7 +214,7 @@ impl Gui { } /// Destroys the plugin's GUI resources, if its GUI is still open. - pub fn destroy(&mut self, plugin: &mut PluginMainThreadHandle) { + pub fn destroy(&mut self, plugin: &PluginMainThreadHandle) { if self.is_open { self.plugin_gui.destroy(plugin); self.is_open = false; diff --git a/host/examples/cpal/src/host/timer.rs b/host/examples/cpal/src/host/timer.rs index b622b1fe..6cfb94dc 100644 --- a/host/examples/cpal/src/host/timer.rs +++ b/host/examples/cpal/src/host/timer.rs @@ -6,13 +6,13 @@ use std::collections::HashMap; use std::time::{Duration, Instant}; impl HostTimerImpl for CpalHostMainThread<'_> { - fn register_timer(&mut self, period_ms: u32) -> Result { + fn register_timer(&self, period_ms: u32) -> Result { Ok(self .timers .register_new(Duration::from_millis(period_ms as u64))) } - fn unregister_timer(&mut self, timer_id: TimerId) -> Result<(), HostError> { + fn unregister_timer(&self, timer_id: TimerId) -> Result<(), HostError> { if self.timers.unregister(timer_id) { Ok(()) } else { @@ -58,7 +58,7 @@ impl Timers { /// Ticks all the registered timers, and run the plugin's callback for all timers that were /// triggered. - pub fn tick_timers(&self, timer_ext: &PluginTimer, plugin: &mut PluginMainThreadHandle) { + pub fn tick_timers(&self, timer_ext: &PluginTimer, plugin: &PluginMainThreadHandle) { for triggered in self.tick_all() { timer_ext.on_timer(plugin, triggered); } diff --git a/host/src/extensions.rs b/host/src/extensions.rs index 61613a75..628343e8 100644 --- a/host/src/extensions.rs +++ b/host/src/extensions.rs @@ -72,6 +72,7 @@ //! This example implements a host supporting the `Latency` extension. //! //! ``` +//! use std::cell::{Cell, OnceCell}; //! use std::sync::OnceLock; //! use clack_host::prelude::*; //! use clack_extensions::latency::*; @@ -98,25 +99,25 @@ //! //! struct MyHostMainThread<'a> { //! shared: &'a MyHostShared, -//! instance: Option>, +//! instance: OnceCell>, //! //! // The latency that is sent to us by the plugin's Latency extension. -//! latency_changed: bool +//! latency_changed: Cell //! } //! //! impl<'a> MainThreadHandler<'a> for MyHostMainThread<'a> { //! // The plugin's instance handle is required to call extension methods. -//! fn initialized(&mut self, instance: InitializedPluginHandle<'a>) { -//! self.instance = Some(instance); +//! fn initialized(&self, instance: InitializedPluginHandle<'a>) { +//! self.instance.set(instance).unwrap(); //! } //! } //! //! impl<'a> HostLatencyImpl for MyHostMainThread<'a> { //! // This method is called by the plugin whenever its latency changed. -//! fn changed(&mut self) { +//! fn changed(&self) { //! // Ensure that the plugin is instantiated and supports the Latency extension. //! if let Some(Some(_latency)) = self.shared.latency_extension.get() { -//! self.latency_changed = true +//! self.latency_changed.set(true) //! } //! } //! } @@ -178,7 +179,7 @@ //! // The `clap_plugin_latency.get` function requires to be called on the `[main-thread]`. //! // Therefore, we will require the `PluginMainThreadHandle` to be passed. //! #[inline] -//! pub fn get(&self, plugin: &mut PluginMainThreadHandle) -> u32 { +//! pub fn get(&self, plugin: &PluginMainThreadHandle) -> u32 { //! match plugin.use_extension(&self.0).get { //! None => 0, //! Some(get) => unsafe { get(plugin.as_raw()) }, @@ -188,7 +189,7 @@ //! //! /// Provides the implementation of the host-side to be called by the plugin. //! pub trait HostLatencyImpl { -//! fn changed(&mut self); +//! fn changed(&self); //! } //! //! // SAFETY: The given struct is the CLAP extension struct for the matching side of this extension. @@ -202,8 +203,8 @@ //! //! unsafe extern "C" fn changed HostHandlers: HostLatencyImpl>>(host: *const clap_host) //! { -//! HostWrapper::::handle(host, |host| { -//! host.main_thread().as_mut().changed(); +//! HostWrapper::::handle_main_thread(host, |host| { +//! host.changed(); //! Ok(()) //! }); //! } diff --git a/host/src/extensions/wrapper.rs b/host/src/extensions/wrapper.rs index 3631f69d..263a3727 100644 --- a/host/src/extensions/wrapper.rs +++ b/host/src/extensions/wrapper.rs @@ -9,6 +9,7 @@ use clap_sys::ext::log::{ use clap_sys::host::clap_host; use clap_sys::plugin::clap_plugin; use std::borrow::Cow; +use std::cell::OnceCell; use std::error::Error; use std::ffi::{CStr, CString}; use std::fmt::{Display, Formatter}; @@ -45,8 +46,8 @@ mod logging; // which means we can never move this again. This must always exist in a Pin. pub struct HostWrapper { audio_processor: UnsafeOptionCell<::AudioProcessor<'static>>, - main_thread: UnsafeOptionCell<::MainThread<'static>>, - shared: Pin::Shared<'static>>>, + main_thread: OnceCell<::MainThread<'static>>, + shared: ::Shared<'static>, // Init stuff init_guard: Once, @@ -120,16 +121,22 @@ impl HostWrapper { } } - /// Returns a raw, non-null pointer to the host's ([`MainThread`](HostHandlers::MainThread)) struct. - /// + /// # Safety + /// TODO + pub unsafe fn handle_main_thread(host: *const clap_host, handler: F) -> Option + where + F: for<'a> FnOnce(&::MainThread<'a>) -> Result, + { + Self::handle(host, |host| host.on_main_thread(handler).transpose()).flatten() + } + /// # Safety /// The caller must ensure this method is only called on the main thread. - /// - /// The pointer is safe to mutably dereference, as long as the caller ensures it is not being - /// aliased, as per usual safety rules. - #[inline] - pub unsafe fn main_thread(&self) -> NonNull<::MainThread<'_>> { - self.main_thread.as_ptr_unchecked().cast() + pub(crate) unsafe fn on_main_thread( + &self, + handler: impl for<'a> FnOnce(&::MainThread<'a>) -> T, + ) -> Option { + Some(handler(self.main_thread.get().as_ref()?)) } /// Returns a raw, non-null pointer to the host's [`AudioProcessor`](HostHandlers::AudioProcessor) @@ -174,25 +181,22 @@ impl HostWrapper { { // We use Arc only because Box implies Unique, which is not the case since the plugin // will effectively hold a shared pointer to this. - let mut wrapper = Arc::new(Self { + let wrapper = Arc::new(Self { audio_processor: UnsafeOptionCell::new(), - main_thread: UnsafeOptionCell::new(), - shared: Box::pin(shared(&())), + main_thread: OnceCell::new(), + shared: shared(&()), init_guard: Once::new(), init_started: AtomicBool::new(false), plugin_ptr: OnceLock::new(), destroy_lock: Arc::new(DestroyLock::new()), }); - // PANIC: we have the only Arc copy of this wrapper data. - let wrapper_mut = Arc::get_mut(&mut wrapper).unwrap(); + // SAFETY: this type guarantees shared lives long enough + let main_thread = main_thread(unsafe { extend_shared_ref(&wrapper.shared) }); - // SAFETY: This type guarantees main thread data cannot outlive shared - unsafe { - wrapper_mut - .main_thread - .put(main_thread(extend_shared_ref(&wrapper_mut.shared))); - } + let Ok(()) = wrapper.main_thread.set(main_thread) else { + unreachable!() + }; // SAFETY: wrapper is the only reference to the data, we can guarantee it will remain pinned // until drop happens. @@ -213,9 +217,9 @@ impl HostWrapper { self.ensure_initializing_called(); let instance = *self.plugin_ptr.get().unwrap(); - // SAFETY: At this point there is no way main_thread could not have been set. - self.main_thread() - .as_mut() + self.main_thread + .get() + .unwrap() .initialized(InitializedPluginHandle::new( self.destroy_lock.clone(), instance, @@ -235,9 +239,9 @@ impl HostWrapper { audio_processor: FA, ) -> Result<(), PluginInstanceError> where - FA: for<'a> FnOnce( + FA: for<'a, 'b> FnOnce( &'a ::Shared<'a>, - &mut ::MainThread<'a>, + &::MainThread<'a>, ) -> ::AudioProcessor<'a>, { if self.audio_processor.is_some() { @@ -249,7 +253,7 @@ impl HostWrapper { unsafe { extend_shared_ref(&self.shared) }, // SAFETY: The user enforces that this is only called on the main thread, and // non-concurrently to any other main-thread method. - unsafe { self.main_thread().cast().as_mut() }, + self.main_thread.get().unwrap(), )); Ok(()) } @@ -262,7 +266,7 @@ impl HostWrapper { &self, drop: impl for<'s> FnOnce( ::AudioProcessor<'s>, - &mut ::MainThread<'s>, + &::MainThread<'s>, ) -> T, ) -> Result { // SAFETY: The user enforces that this is called and non-concurrently to any other audio-thread method. @@ -272,7 +276,7 @@ impl HostWrapper { audio_processor, // SAFETY: The user enforces that this is only called on the main thread, and // non-concurrently to any other main-thread method. - unsafe { self.main_thread().cast().as_mut() }, + self.main_thread.get().unwrap(), )), } } diff --git a/host/src/host.rs b/host/src/host.rs index 6f031491..f2da7f18 100644 --- a/host/src/host.rs +++ b/host/src/host.rs @@ -83,6 +83,7 @@ //! //! use std::sync::atomic::{AtomicBool, Ordering}; //! use std::sync::OnceLock; +//! use std::cell::{Cell, OnceCell}; //! use std::ffi::CStr; //! //! #[derive(Default)] @@ -119,21 +120,21 @@ //! //! struct MyHostMainThread<'a> { //! shared: &'a MyHostShared, -//! instance: Option>, +//! instance: OnceCell>, //! -//! latency_changed: bool +//! latency_changed: Cell //! } //! //! impl<'a> MainThreadHandler<'a> for MyHostMainThread<'a> { -//! fn initialized(&mut self, instance: InitializedPluginHandle<'a>) { -//! self.instance = Some(instance); +//! fn initialized(&self, instance: InitializedPluginHandle<'a>) { +//! self.instance.set(instance); //! } //! } //! //! impl<'a> HostLatencyImpl for MyHostMainThread<'a> { -//! fn changed(&mut self) { +//! fn changed(&self) { //! if let Some(Some(_latency)) = self.shared.latency_extension.get() { -//! self.latency_changed = true +//! self.latency_changed.set(true) //! } //! } //! } @@ -164,7 +165,7 @@ //! //! let mut plugin_instance = PluginInstance::::new( //! |_| MyHostShared::default(), -//! |shared| MyHostMainThread { shared, instance: None, latency_changed: false }, +//! |shared| MyHostMainThread { shared, instance: OnceCell::new(), latency_changed: false.into() }, //! &entry, //! // We're hard-coding a specific plugin to load for this example //! c"com.u-he.diva", @@ -216,7 +217,7 @@ pub trait MainThreadHandler<'a>: 'a { /// handler's lifetime. #[inline] #[allow(unused)] - fn initialized(&mut self, instance: InitializedPluginHandle<'a>) {} + fn initialized(&self, instance: InitializedPluginHandle<'a>) {} } /// Host data and callbacks that are tied to `[audio-thread]` operations. diff --git a/host/src/plugin.rs b/host/src/plugin.rs index 07210871..caa22869 100644 --- a/host/src/plugin.rs +++ b/host/src/plugin.rs @@ -78,7 +78,7 @@ impl PluginInstance { /// } /// /// impl<'a> MainThreadHandler<'a> for MyHostMainThread { - /// fn initialized(&mut self, instance: InitializedPluginHandle<'a>) { + /// fn initialized(&self, instance: InitializedPluginHandle<'a>) { /// // Called whn the plugin has been fully initialized. /// } /// } @@ -159,7 +159,7 @@ impl PluginInstance { where FA: for<'a> FnOnce( &'a ::Shared<'a>, - &mut ::MainThread<'a>, + &::MainThread<'a>, ) -> ::AudioProcessor<'a>, { configuration.validate(); @@ -237,7 +237,7 @@ impl PluginInstance { where D: for<'s> FnOnce( ::AudioProcessor<'s>, - &mut ::MainThread<'s>, + &::MainThread<'s>, ) -> T, { if !Arc::ptr_eq(&self.inner, &processor.inner) { @@ -276,7 +276,7 @@ impl PluginInstance { where D: for<'s> FnOnce( ::AudioProcessor<'s>, - &mut ::MainThread<'s>, + &::MainThread<'s>, ) -> T, { let wrapper = @@ -338,30 +338,17 @@ impl PluginInstance { /// type is self-referential: both the [`HostHandlers`] and the plugin's instance data hold /// references to each other, and both are owned by this type. #[inline] - pub fn access_handler<'s, R>( - &'s self, - access: impl for<'a> FnOnce(&'s ::MainThread<'a>) -> R, + pub fn access_handler( + &self, + access: impl for<'a> FnOnce(&::MainThread<'a>) -> R, ) -> R { - // SAFETY: we take &self, the only reference to the wrapper on the main thread, therefore - // we can guarantee there are no mutable reference anywhere - unsafe { access(self.inner.wrapper().main_thread().as_ref()) } - } + // SAFETY: This type guarantees it can only be called on the main thread + let Some(result) = (unsafe { self.inner.wrapper().on_main_thread(access) }) else { + // PANIC: main_thread can only be None if called from within init() + unreachable!() + }; - /// Access an exclusive `&mut` reference to [`MainThreadHandler`] instance associated to this plugin instance using the given callback. - /// - /// The callback's return value `R` is returned directly by this method. - /// - /// Accessing the [`HostHandlers`] types can only be done with accessor callbacks because this - /// type is self-referential: both the [`HostHandlers`] and the plugin's instance data hold - /// references to each other, and both are owned by this type. - #[inline] - pub fn access_handler_mut<'s, R>( - &'s mut self, - access: impl for<'a> FnOnce(&'s mut ::MainThread<'a>) -> R, - ) -> R { - // SAFETY: we take &mut self, the only reference to the wrapper on the main thread, therefore - // we can guarantee there are no mutable reference anywhere - unsafe { access(self.inner.wrapper().main_thread().as_mut()) } + result } /// Returns a thread-safe handle to the plugin. diff --git a/host/src/plugin/handle.rs b/host/src/plugin/handle.rs index 94be2ad5..62bc43de 100644 --- a/host/src/plugin/handle.rs +++ b/host/src/plugin/handle.rs @@ -3,7 +3,7 @@ use clack_common::plugin::PluginDescriptor; use clap_sys::plugin::clap_plugin; use std::fmt::{Debug, Formatter}; use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use std::ptr::NonNull; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, RwLock}; @@ -12,7 +12,7 @@ use std::sync::{Arc, RwLock}; /// /// This can be used to make requests to the plugin that can only be made in the main thread, which /// is required for e.g. some extensions. -#[derive(Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq)] #[repr(transparent)] pub struct PluginMainThreadHandle<'a> { raw: NonNull, @@ -86,7 +86,7 @@ impl<'a> Deref for PluginMainThreadHandle<'a> { /// /// This is used by some extensions that e.g. require a function to be called on the main thread only /// if the plugin is inactive, and on the audio thread if it is active. -#[derive(Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq)] #[repr(transparent)] pub struct InactivePluginMainThreadHandle<'a> { raw: NonNull, @@ -154,7 +154,7 @@ impl<'a> InactivePluginMainThreadHandle<'a> { /// Only one of the [`InactivePluginMainThreadHandle`] and [`PluginMainThreadHandle`] may be /// used at the same time. #[inline] - pub const fn as_main_thread(&mut self) -> &mut PluginMainThreadHandle<'a> { + pub const fn as_main_thread(&mut self) -> &PluginMainThreadHandle<'a> { // SAFETY: this cast is valid since both types are just a NonNull and repr(transparent) unsafe { &mut *(self as *mut Self as *mut PluginMainThreadHandle<'a>) } } @@ -176,13 +176,6 @@ impl<'a> Deref for InactivePluginMainThreadHandle<'a> { } } -impl DerefMut for InactivePluginMainThreadHandle<'_> { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - self.as_main_thread() - } -} - /// A thread-safe handle to the plugin instance. /// /// This can be used to make requests to the plugin that support being made from any threads. diff --git a/host/src/plugin/instance.rs b/host/src/plugin/instance.rs index cb857b55..41fd9b44 100644 --- a/host/src/plugin/instance.rs +++ b/host/src/plugin/instance.rs @@ -118,7 +118,7 @@ impl PluginInstanceInner { where FA: for<'a> FnOnce( &'a ::Shared<'a>, - &mut ::MainThread<'a>, + &::MainThread<'a>, ) -> ::AudioProcessor<'a>, { let activate = self @@ -160,7 +160,7 @@ impl PluginInstanceInner { &mut self, drop: impl for<'s> FnOnce( ::AudioProcessor<'s>, - &mut ::MainThread<'s>, + &::MainThread<'s>, ) -> T, ) -> Result { if !self.is_active() { diff --git a/host/src/util.rs b/host/src/util.rs index 080b04a1..d887d69d 100644 --- a/host/src/util.rs +++ b/host/src/util.rs @@ -34,15 +34,6 @@ impl UnsafeOptionCell { unsafe { Some(NonNull::new_unchecked(ptr)) } } - /// # Safety - /// Users must ensure the option is initialized to a value. - pub unsafe fn as_ptr_unchecked(&self) -> NonNull { - let ptr = self.inner.get().cast(); - - // SAFETY: this pointer comes from an UnsafeCell, it cannot be null. - unsafe { NonNull::new_unchecked(ptr) } - } - /// # Safety /// Users must ensure this method is never called concurrently with itself, [`Self::take`], or /// while any reference to `T` is still being held. diff --git a/host/tests/call-in-destruction.rs b/host/tests/call-in-destruction.rs index a72bba95..dbce7880 100644 --- a/host/tests/call-in-destruction.rs +++ b/host/tests/call-in-destruction.rs @@ -4,6 +4,7 @@ use clack_common::stream::{InputStream, OutputStream}; use clack_extensions::state::{PluginState, PluginStateImpl}; use clack_host::prelude::*; use clack_plugin::prelude::*; +use std::cell::OnceCell; use std::io::Write; use std::sync::OnceLock; @@ -87,19 +88,19 @@ impl<'a> SharedHandler<'a> for MyHostShared<'a> { } struct MyHostMainThread<'a> { - instance: Option>, + instance: OnceCell>, } impl<'a> MainThreadHandler<'a> for MyHostMainThread<'a> { - fn initialized(&mut self, instance: InitializedPluginHandle<'a>) { + fn initialized(&self, instance: InitializedPluginHandle<'a>) { assert!(instance.get_extension::().is_some()); - self.instance = Some(instance) + self.instance.set(instance).unwrap(); } } impl Drop for MyHostMainThread<'_> { fn drop(&mut self) { - let instance = self.instance.as_ref().unwrap(); + let instance = self.instance.get().unwrap(); assert!(instance.get_extension::().is_none()); } } @@ -114,7 +115,9 @@ fn can_call_host_methods_during_init() { |_| MyHostShared { init: OnceLock::new(), }, - |_| MyHostMainThread { instance: None }, + |_| MyHostMainThread { + instance: OnceCell::new(), + }, &entry, c"my.plugin", &host, diff --git a/host/tests/reentrant-init.rs b/host/tests/reentrant-init.rs index 36119424..7beb2b1c 100644 --- a/host/tests/reentrant-init.rs +++ b/host/tests/reentrant-init.rs @@ -3,6 +3,7 @@ use clack_extensions::timer::{HostTimer, HostTimerImpl, PluginTimer, PluginTimerImpl, TimerId}; use clack_host::prelude::*; use clack_plugin::prelude::*; +use std::cell::Cell; use std::sync::OnceLock; struct MyPlugin; @@ -38,11 +39,11 @@ impl DefaultPluginFactory for MyPlugin { } fn new_main_thread( - mut host: HostMainThreadHandle, + host: HostMainThreadHandle, _shared: &(), ) -> Result { let timer: HostTimer = host.get_extension().unwrap(); - let timer_id = timer.register_timer(&mut host, 1_000)?; + let timer_id = timer.register_timer(&host, 1_000)?; assert_eq!(timer_id, TimerId(5)); Ok(MyPluginMainThread) } @@ -82,15 +83,15 @@ impl<'a> SharedHandler<'a> for MyHostShared<'a> { struct MyHostMainThread<'a> { shared: &'a MyHostShared<'a>, - timer_registered: bool, + timer_registered: Cell, } impl<'a> MainThreadHandler<'a> for MyHostMainThread<'a> { - fn initialized(&mut self, _instance: InitializedPluginHandle<'a>) {} + fn initialized(&self, _instance: InitializedPluginHandle<'a>) {} } impl HostTimerImpl for MyHostMainThread<'_> { - fn register_timer(&mut self, period_ms: u32) -> Result { + fn register_timer(&self, period_ms: u32) -> Result { assert_eq!(period_ms, 1000); let handle = self @@ -103,11 +104,11 @@ impl HostTimerImpl for MyHostMainThread<'_> { .get_extension::() .expect("Plugin should implement Timer extension!"); - self.timer_registered = true; + self.timer_registered.set(true); Ok(TimerId(5)) } - fn unregister_timer(&mut self, _timer_id: TimerId) -> Result<(), HostError> { + fn unregister_timer(&self, _timer_id: TimerId) -> Result<(), HostError> { unimplemented!() } } @@ -123,7 +124,7 @@ fn can_call_host_methods_during_init() { }, |shared| MyHostMainThread { shared, - timer_registered: false, + timer_registered: false.into(), }, &entry, c"my.plugin", @@ -132,5 +133,5 @@ fn can_call_host_methods_during_init() { .unwrap(); // Timer should have already been registered by the plugin during init(). - assert!(instance.access_handler(|h| h.timer_registered)); + assert!(instance.access_handler(|h| h.timer_registered.get())); } diff --git a/plugin/examples/gain-gui/tests/test_gain.rs b/plugin/examples/gain-gui/tests/test_gain.rs index 5e63dd70..7eb2bc45 100644 --- a/plugin/examples/gain-gui/tests/test_gain.rs +++ b/plugin/examples/gain-gui/tests/test_gain.rs @@ -51,16 +51,16 @@ pub fn it_works() { ) .unwrap(); - let mut plugin_main_thread = plugin.plugin_handle(); + let plugin_main_thread = plugin.plugin_handle(); let ports_ext = plugin_main_thread .get_extension::() .unwrap(); - assert_eq!(1, ports_ext.count(&mut plugin_main_thread, true)); - assert_eq!(1, ports_ext.count(&mut plugin_main_thread, false)); + assert_eq!(1, ports_ext.count(&plugin_main_thread, true)); + assert_eq!(1, ports_ext.count(&plugin_main_thread, false)); let mut buf = AudioPortInfoBuffer::new(); let info = ports_ext - .get(&mut plugin_main_thread, 0, false, &mut buf) + .get(&plugin_main_thread, 0, false, &mut buf) .unwrap(); assert_eq!(info.id, 0); diff --git a/plugin/examples/gain-presets/tests/test_gain.rs b/plugin/examples/gain-presets/tests/test_gain.rs index 3103fde7..4b350afc 100644 --- a/plugin/examples/gain-presets/tests/test_gain.rs +++ b/plugin/examples/gain-presets/tests/test_gain.rs @@ -52,16 +52,16 @@ pub fn it_works() { ) .unwrap(); - let mut plugin_main_thread = plugin.plugin_handle(); + let plugin_main_thread = plugin.plugin_handle(); let ports_ext = plugin_main_thread .get_extension::() .unwrap(); - assert_eq!(1, ports_ext.count(&mut plugin_main_thread, true)); - assert_eq!(1, ports_ext.count(&mut plugin_main_thread, false)); + assert_eq!(1, ports_ext.count(&plugin_main_thread, true)); + assert_eq!(1, ports_ext.count(&plugin_main_thread, false)); let mut buf = AudioPortInfoBuffer::new(); let info = ports_ext - .get(&mut plugin_main_thread, 0, false, &mut buf) + .get(&plugin_main_thread, 0, false, &mut buf) .unwrap(); assert_eq!(info.id, 0); diff --git a/plugin/examples/gain/tests/test_gain.rs b/plugin/examples/gain/tests/test_gain.rs index ad895bd4..30dbf019 100644 --- a/plugin/examples/gain/tests/test_gain.rs +++ b/plugin/examples/gain/tests/test_gain.rs @@ -49,16 +49,16 @@ pub fn it_works() { ) .unwrap(); - let mut plugin_main_thread = plugin.plugin_handle(); + let plugin_main_thread = plugin.plugin_handle(); let ports_ext = plugin_main_thread .get_extension::() .unwrap(); - assert_eq!(1, ports_ext.count(&mut plugin_main_thread, true)); - assert_eq!(1, ports_ext.count(&mut plugin_main_thread, false)); + assert_eq!(1, ports_ext.count(&plugin_main_thread, true)); + assert_eq!(1, ports_ext.count(&plugin_main_thread, false)); let mut buf = AudioPortInfoBuffer::new(); let info = ports_ext - .get(&mut plugin_main_thread, 0, false, &mut buf) + .get(&plugin_main_thread, 0, false, &mut buf) .unwrap(); assert_eq!(info.id, 0); diff --git a/plugin/src/host.rs b/plugin/src/host.rs index 66e59c95..e8d016f8 100644 --- a/plugin/src/host.rs +++ b/plugin/src/host.rs @@ -302,6 +302,7 @@ impl<'a> Deref for HostSharedHandle<'a> { /// A main-thread handle to the host. /// /// This can be used to perform requests to the host that can only be made from the main thread. +#[derive(Copy, Clone)] #[repr(transparent)] pub struct HostMainThreadHandle<'a> { raw: NonNull,