use clack_common::extensions::{Extension, PluginExtensionSide, RawExtension};
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::ptr::NonNull;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
#[derive(Eq, PartialEq)]
#[repr(transparent)]
pub struct PluginMainThreadHandle<'a> {
raw: NonNull<clap_plugin>,
lifetime: PhantomData<&'a clap_plugin>,
}
impl<'a> PluginMainThreadHandle<'a> {
pub(crate) const unsafe fn new(raw: NonNull<clap_plugin>) -> Self {
Self {
raw,
lifetime: PhantomData,
}
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_plugin {
unsafe { self.raw.as_ref() }
}
#[inline]
pub const fn as_raw_ptr(&self) -> *const clap_plugin {
self.raw.as_ptr()
}
#[inline]
pub const fn shared(&self) -> PluginSharedHandle<'a> {
unsafe { PluginSharedHandle::new(self.raw) }
}
#[inline]
pub const fn as_shared(&self) -> &PluginSharedHandle<'a> {
unsafe { &*(self as *const Self as *const PluginSharedHandle<'a>) }
}
}
impl Debug for PluginMainThreadHandle<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "PluginMainThreadHandle ({:p})", self.raw)
}
}
impl<'a> Deref for PluginMainThreadHandle<'a> {
type Target = PluginSharedHandle<'a>;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_shared()
}
}
#[derive(Eq, PartialEq)]
#[repr(transparent)]
pub struct InactivePluginMainThreadHandle<'a> {
raw: NonNull<clap_plugin>,
lifetime: PhantomData<&'a clap_plugin>,
}
impl<'a> InactivePluginMainThreadHandle<'a> {
pub(crate) const unsafe fn new(raw: NonNull<clap_plugin>) -> Self {
Self {
raw,
lifetime: PhantomData,
}
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_plugin {
unsafe { self.raw.as_ref() }
}
#[inline]
pub const fn as_raw_ptr(&self) -> *const clap_plugin {
self.raw.as_ptr()
}
#[inline]
pub const fn shared(&self) -> PluginSharedHandle<'a> {
unsafe { PluginSharedHandle::new(self.raw) }
}
#[inline]
pub const fn as_shared(&self) -> &PluginSharedHandle<'a> {
unsafe { &*(self as *const Self as *const PluginSharedHandle<'a>) }
}
#[inline]
const fn as_main_thread_ref(&self) -> &PluginMainThreadHandle<'a> {
unsafe { &*(self as *const Self as *const PluginMainThreadHandle<'a>) }
}
#[inline]
pub const fn as_main_thread(&mut self) -> &mut PluginMainThreadHandle<'a> {
unsafe { &mut *(self as *mut Self as *mut PluginMainThreadHandle<'a>) }
}
}
impl Debug for InactivePluginMainThreadHandle<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "InactivePluginMainThreadHandle ({:p})", self.raw)
}
}
impl<'a> Deref for InactivePluginMainThreadHandle<'a> {
type Target = PluginMainThreadHandle<'a>;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_main_thread_ref()
}
}
impl DerefMut for InactivePluginMainThreadHandle<'_> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_main_thread()
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(transparent)]
pub struct PluginSharedHandle<'a> {
raw: NonNull<clap_plugin>,
lifetime: PhantomData<&'a clap_plugin>,
}
unsafe impl Send for PluginSharedHandle<'_> {}
unsafe impl Sync for PluginSharedHandle<'_> {}
impl<'a> PluginSharedHandle<'a> {
pub(crate) const unsafe fn new(raw: NonNull<clap_plugin>) -> Self {
Self {
raw,
lifetime: PhantomData,
}
}
pub const fn descriptor(&self) -> Option<&'a PluginDescriptor> {
let Some(descriptor) = (unsafe { self.as_raw().desc.as_ref() }) else {
return None;
};
Some(unsafe { PluginDescriptor::from_raw(descriptor) })
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_plugin {
unsafe { self.raw.as_ref() }
}
#[inline]
pub const fn as_raw_ptr(&self) -> *const clap_plugin {
self.raw.as_ptr()
}
pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
let identifier = const { E::IDENTIFIERS.first().unwrap() };
let ext = unsafe { self.as_raw().get_extension?(self.raw.as_ptr(), identifier.as_ptr()) };
let ext = NonNull::new(ext as *mut _)?;
let raw = unsafe { RawExtension::from_raw_plugin_extension(ext, self.raw) };
unsafe { Some(E::from_raw(raw)) }
}
#[inline]
pub fn use_extension<E: Sized>(
&self,
extension: &RawExtension<PluginExtensionSide, E>,
) -> &'a E {
if self.raw != extension.plugin_ptr() {
mismatched_instance();
}
unsafe { extension.as_ptr().as_ref() }
}
}
impl Debug for PluginSharedHandle<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "PluginSharedHandle ({:p})", self.raw)
}
}
#[derive(Eq, PartialEq)]
#[repr(transparent)]
pub struct PluginAudioProcessorHandle<'a> {
raw: NonNull<clap_plugin>,
lifetime: PhantomData<&'a clap_plugin>,
}
unsafe impl Send for PluginAudioProcessorHandle<'_> {}
impl<'a> PluginAudioProcessorHandle<'a> {
pub(crate) const fn new(raw: NonNull<clap_plugin>) -> Self {
Self {
raw,
lifetime: PhantomData,
}
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_plugin {
unsafe { self.raw.as_ref() }
}
#[inline]
pub const fn as_raw_ptr(&self) -> *const clap_plugin {
self.raw.as_ptr()
}
#[inline]
pub const fn shared(&self) -> PluginSharedHandle<'a> {
PluginSharedHandle {
raw: self.raw,
lifetime: PhantomData,
}
}
#[inline]
pub const fn as_shared(&self) -> &PluginSharedHandle<'a> {
unsafe { &*(self as *const Self as *const PluginSharedHandle<'a>) }
}
}
impl<'a> Deref for PluginAudioProcessorHandle<'a> {
type Target = PluginSharedHandle<'a>;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_shared()
}
}
impl Debug for PluginAudioProcessorHandle<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "PluginAudioProcessorHandle ({:p})", self.raw)
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct InitializingPluginHandle<'a> {
inner: RemoteHandleInner,
lifetime: PhantomData<&'a clap_plugin>,
}
impl<'a> InitializingPluginHandle<'a> {
pub(crate) const unsafe fn new(lock: Arc<DestroyLock>, instance: NonNull<clap_plugin>) -> Self {
Self {
lifetime: PhantomData,
inner: RemoteHandleInner { instance, lock },
}
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_plugin {
unsafe { self.inner.instance.as_ref() }
}
#[inline]
pub const fn as_raw_ptr(&self) -> *const clap_plugin {
self.inner.instance.as_ptr()
}
pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
self.inner.get_extension()
}
}
impl Debug for InitializingPluginHandle<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "InitializingPluginHandle ({:p})", self.inner.instance)
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct InitializedPluginHandle<'a> {
inner: RemoteHandleInner,
lifetime: PhantomData<&'a clap_plugin>,
}
impl<'a> InitializedPluginHandle<'a> {
pub(crate) const unsafe fn new(lock: Arc<DestroyLock>, instance: NonNull<clap_plugin>) -> Self {
Self {
lifetime: PhantomData,
inner: RemoteHandleInner { instance, lock },
}
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_plugin {
unsafe { self.inner.instance.as_ref() }
}
#[inline]
pub const fn as_raw_ptr(&self) -> *const clap_plugin {
self.inner.instance.as_ptr()
}
#[inline]
pub fn access<T>(&self, f: impl FnOnce(PluginSharedHandle) -> T) -> Option<T> {
self.inner.access(f)
}
pub fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
self.inner.get_extension()
}
}
impl Debug for InitializedPluginHandle<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "InitializingPluginHandle ({:p})", self.inner.instance)
}
}
#[derive(Clone)]
struct RemoteHandleInner {
lock: Arc<DestroyLock>,
instance: NonNull<clap_plugin>,
}
impl RemoteHandleInner {
fn access<T>(&self, f: impl FnOnce(PluginSharedHandle) -> T) -> Option<T> {
self.lock.hold_off_destruction(|| {
let handle = unsafe { PluginSharedHandle::new(self.instance) };
f(handle)
})
}
#[inline]
fn get_extension<E: Extension<ExtensionSide = PluginExtensionSide>>(&self) -> Option<E> {
self.access(|handle| handle.get_extension())?
}
}
impl PartialEq for RemoteHandleInner {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.instance == other.instance
}
}
impl Eq for RemoteHandleInner {}
unsafe impl Send for RemoteHandleInner {}
unsafe impl Sync for RemoteHandleInner {}
pub(crate) struct DestroyLock {
is_destroying: AtomicBool,
lock: RwLock<bool>,
}
impl DestroyLock {
pub(crate) fn new() -> Self {
Self {
is_destroying: AtomicBool::new(false),
lock: RwLock::new(false),
}
}
pub(crate) fn start_destroying(&self) {
self.is_destroying.store(true, Ordering::SeqCst);
let mut guard = self.lock.write().unwrap_or_else(|err| err.into_inner());
*guard = true;
}
fn hold_off_destruction<T>(&self, handler: impl FnOnce() -> T) -> Option<T> {
if self.is_destroying.load(Ordering::SeqCst) {
return None;
}
let guard = self.lock.read().unwrap_or_else(|err| err.into_inner());
if *guard {
return None;
}
let result = handler();
drop(guard);
Some(result)
}
}
#[cold]
const fn mismatched_instance() -> ! {
panic!("Given plugin instance handle doesn't match the extension pointer it was used on.")
}