From af77d45877f0a9640bba526c6fba5c628ad0ca95 Mon Sep 17 00:00:00 2001
From: Robbert van der Helm <mail@robbertvanderhelm.nl>
Date: Mon, 28 Feb 2022 20:39:15 +0100
Subject: [PATCH] Add a Send+Sync wrapper for CLAP object pointers

We'll need this for the extensions.
---
 src/wrapper/clap.rs        |  1 +
 src/wrapper/clap/plugin.rs | 13 ++++++-------
 src/wrapper/clap/util.rs   | 28 ++++++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 7 deletions(-)
 create mode 100644 src/wrapper/clap/util.rs

diff --git a/src/wrapper/clap.rs b/src/wrapper/clap.rs
index 8edfefa3..884b44d8 100644
--- a/src/wrapper/clap.rs
+++ b/src/wrapper/clap.rs
@@ -2,6 +2,7 @@ mod context;
 mod descriptor;
 mod factory;
 mod plugin;
+mod util;
 
 /// Re-export for the wrapper.
 pub use self::factory::Factory;
diff --git a/src/wrapper/clap/plugin.rs b/src/wrapper/clap/plugin.rs
index a6f63795..7f56bff4 100644
--- a/src/wrapper/clap/plugin.rs
+++ b/src/wrapper/clap/plugin.rs
@@ -13,6 +13,7 @@ use std::thread::{self, ThreadId};
 
 use super::context::WrapperProcessContext;
 use super::descriptor::PluginDescriptor;
+use super::util::ClapPtr;
 use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
 use crate::plugin::{BufferConfig, BusConfig, ClapPlugin};
 use crate::NoteEvent;
@@ -43,7 +44,7 @@ pub struct Wrapper<P: ClapPlugin> {
     /// TODO: Implement the latency extension.
     pub current_latency: AtomicU32,
 
-    host_callback: HostCallback,
+    host_callback: ClapPtr<clap_host>,
     /// Needs to be boxed because the plugin object is supposed to contain a static reference to
     /// this.
     plugin_descriptor: Box<PluginDescriptor<P>>,
@@ -88,8 +89,8 @@ impl<P: ClapPlugin> EventLoop<Task, Wrapper<P>> for Wrapper<P> {
             let success = self.tasks.push(task).is_ok();
             if success {
                 // CLAP lets us use the host's event loop instead of having to implement our own
-                let host = self.host_callback.0;
-                unsafe { ((*host).request_callback)(host) };
+                let host = &self.host_callback;
+                unsafe { (host.request_callback)(&**host) };
             }
 
             success
@@ -108,13 +109,11 @@ impl<P: ClapPlugin> MainThreadExecutor<Task> for Wrapper<P> {
     }
 }
 
-unsafe impl Send for HostCallback {}
-unsafe impl Sync for HostCallback {}
-
 impl<P: ClapPlugin> Wrapper<P> {
     pub fn new(host_callback: *const clap_host) -> Self {
         let plugin_descriptor = Box::new(PluginDescriptor::default());
 
+        assert!(!host_callback.is_null());
         Self {
             clap_plugin: clap_plugin {
                 // This needs to live on the heap because the plugin object contains a direct
@@ -145,7 +144,7 @@ impl<P: ClapPlugin> Wrapper<P> {
             input_events: RwLock::new(VecDeque::with_capacity(512)),
             current_latency: AtomicU32::new(0),
 
-            host_callback: HostCallback(host_callback),
+            host_callback: unsafe { ClapPtr::new(host_callback) },
             plugin_descriptor,
 
             tasks: ArrayQueue::new(TASK_QUEUE_CAPACITY),
diff --git a/src/wrapper/clap/util.rs b/src/wrapper/clap/util.rs
new file mode 100644
index 00000000..6c36caf5
--- /dev/null
+++ b/src/wrapper/clap/util.rs
@@ -0,0 +1,28 @@
+use std::ops::Deref;
+
+/// Send+Sync wrapper around CLAP host extension pointers.
+pub struct ClapPtr<T> {
+    inner: *const T,
+}
+
+impl<T> Deref for ClapPtr<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*self.inner }
+    }
+}
+
+unsafe impl<T> Send for ClapPtr<T> {}
+unsafe impl<T> Sync for ClapPtr<T> {}
+
+impl<T> ClapPtr<T> {
+    /// Create a wrapper around a CLAP object pointer.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must point to a valid object with a lifetime that exceeds this object.
+    pub unsafe fn new(ptr: *const T) -> Self {
+        Self { inner: ptr }
+    }
+}