use clack_common::extensions::{Extension, HostExtensionSide, RawExtension};
use clack_common::utils::ClapVersion;
use clap_sys::host::clap_host;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::NonNull;
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct HostInfo<'a> {
raw: NonNull<clap_host>,
_lifetime: PhantomData<&'a clap_host>,
}
impl<'a> HostInfo<'a> {
#[inline]
pub const unsafe fn from_raw(raw: NonNull<clap_host>) -> Self {
Self {
raw,
_lifetime: PhantomData,
}
}
#[inline]
pub const fn clap_version(&self) -> ClapVersion {
ClapVersion::from_raw(self.as_raw().clap_version)
}
pub const fn name(&self) -> Option<&'a CStr> {
let Some(ptr) = NonNull::new(self.as_raw().name as *mut _) else {
return None;
};
Some(unsafe { CStr::from_ptr(ptr.as_ptr()) })
}
pub const fn vendor(&self) -> Option<&'a CStr> {
let Some(ptr) = NonNull::new(self.as_raw().vendor as *mut _) else {
return None;
};
Some(unsafe { CStr::from_ptr(ptr.as_ptr()) })
}
pub const fn url(&self) -> Option<&'a CStr> {
let Some(ptr) = NonNull::new(self.as_raw().url as *mut _) else {
return None;
};
Some(unsafe { CStr::from_ptr(ptr.as_ptr()) })
}
pub const fn version(&self) -> Option<&'a CStr> {
let Some(ptr) = NonNull::new(self.as_raw().version as *mut _) else {
return None;
};
Some(unsafe { CStr::from_ptr(ptr.as_ptr()) })
}
pub fn get_extension<E: Extension<ExtensionSide = HostExtensionSide>>(&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_host_extension(ext, self.raw) };
unsafe { Some(E::from_raw(raw)) }
}
#[inline]
pub(crate) const unsafe fn to_handle(self) -> HostSharedHandle<'a> {
HostSharedHandle {
raw: self.raw,
_lifetime: PhantomData,
}
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_host {
unsafe { self.raw.as_ref() }
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct HostSharedHandle<'a> {
raw: NonNull<clap_host>,
_lifetime: PhantomData<&'a clap_host>,
}
unsafe impl Send for HostSharedHandle<'_> {}
unsafe impl Sync for HostSharedHandle<'_> {}
impl<'a> HostSharedHandle<'a> {
#[inline]
pub const fn info(&self) -> HostInfo<'a> {
HostInfo {
raw: self.raw,
_lifetime: PhantomData,
}
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_host {
unsafe { self.raw.as_ref() }
}
#[inline]
pub const fn as_info(&self) -> &HostInfo<'a> {
unsafe { &*(self as *const Self as *const HostInfo<'a>) }
}
#[inline]
pub fn request_restart(&self) {
if let Some(request_restart) = self.as_raw().request_restart {
unsafe { request_restart(self.raw.as_ptr()) }
}
}
#[inline]
pub fn request_process(&self) {
if let Some(request_process) = self.as_raw().request_process {
unsafe { request_process(self.raw.as_ptr()) }
}
}
#[inline]
pub fn request_callback(&self) {
if let Some(request_callback) = self.as_raw().request_callback {
unsafe { request_callback(self.raw.as_ptr()) }
}
}
#[inline]
pub const unsafe fn as_main_thread_unchecked(&self) -> HostMainThreadHandle<'a> {
HostMainThreadHandle {
raw: self.raw,
_lifetime: PhantomData,
}
}
#[inline]
pub const unsafe fn as_audio_processor_unchecked(&self) -> HostAudioProcessorHandle<'a> {
HostAudioProcessorHandle {
raw: self.raw,
_lifetime: PhantomData,
}
}
#[inline]
pub fn use_extension<E: Sized>(&self, extension: &RawExtension<HostExtensionSide, E>) -> &'a E {
if self.raw != extension.host_ptr() {
mismatched_instance();
}
unsafe { extension.as_ptr().as_ref() }
}
#[inline]
pub unsafe fn from_raw(raw: NonNull<clap_host>) -> Self {
Self {
raw,
_lifetime: PhantomData,
}
}
#[inline]
pub unsafe fn with_arbitrary_lifetime<'b>(&self) -> HostSharedHandle<'b> {
HostSharedHandle {
raw: self.raw,
_lifetime: PhantomData,
}
}
}
impl<'a> From<HostSharedHandle<'a>> for HostInfo<'a> {
#[inline]
fn from(h: HostSharedHandle<'a>) -> Self {
h.info()
}
}
impl<'a> Deref for HostSharedHandle<'a> {
type Target = HostInfo<'a>;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_info()
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct HostMainThreadHandle<'a> {
raw: NonNull<clap_host>,
_lifetime: PhantomData<&'a clap_host>,
}
impl<'a> HostMainThreadHandle<'a> {
#[inline]
pub const fn shared(&self) -> HostSharedHandle<'a> {
HostSharedHandle {
raw: self.raw,
_lifetime: PhantomData,
}
}
#[inline]
pub const fn as_shared(&self) -> &HostSharedHandle<'a> {
unsafe { &*(self as *const Self as *const HostSharedHandle<'a>) }
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_host {
unsafe { self.raw.as_ref() }
}
#[inline]
pub unsafe fn from_raw(raw: NonNull<clap_host>) -> Self {
Self {
raw,
_lifetime: PhantomData,
}
}
#[inline]
pub unsafe fn with_arbitrary_lifetime<'b>(&self) -> HostMainThreadHandle<'b> {
HostMainThreadHandle {
raw: self.raw,
_lifetime: PhantomData,
}
}
}
impl<'a> From<HostMainThreadHandle<'a>> for HostSharedHandle<'a> {
#[inline]
fn from(h: HostMainThreadHandle<'a>) -> Self {
h.shared()
}
}
impl<'a> Deref for HostMainThreadHandle<'a> {
type Target = HostSharedHandle<'a>;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_shared()
}
}
#[repr(transparent)]
pub struct HostAudioProcessorHandle<'a> {
raw: NonNull<clap_host>,
_lifetime: PhantomData<&'a clap_host>,
}
unsafe impl Send for HostAudioProcessorHandle<'_> {}
impl<'a> HostAudioProcessorHandle<'a> {
#[inline]
pub const fn shared(&self) -> HostSharedHandle<'a> {
HostSharedHandle {
raw: self.raw,
_lifetime: PhantomData,
}
}
#[inline]
pub const fn as_raw(&self) -> &'a clap_host {
unsafe { self.raw.as_ref() }
}
#[inline]
pub const fn as_shared(&self) -> &HostSharedHandle<'a> {
unsafe { &*(self as *const Self as *const HostSharedHandle<'a>) }
}
#[inline]
pub unsafe fn from_raw(raw: NonNull<clap_host>) -> Self {
Self {
raw,
_lifetime: PhantomData,
}
}
#[inline]
pub unsafe fn with_arbitrary_lifetime<'b>(&self) -> HostAudioProcessorHandle<'b> {
HostAudioProcessorHandle {
raw: self.raw,
_lifetime: PhantomData,
}
}
}
impl<'a> From<HostAudioProcessorHandle<'a>> for HostSharedHandle<'a> {
#[inline]
fn from(h: HostAudioProcessorHandle<'a>) -> Self {
h.shared()
}
}
impl<'a> Deref for HostAudioProcessorHandle<'a> {
type Target = HostSharedHandle<'a>;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_shared()
}
}
#[inline(never)]
#[cold]
const fn mismatched_instance() -> ! {
panic!("Given host handle doesn't match the extension pointer it was used on.")
}