use std::ffi::c_void;
use std::marker::PhantomData;
use vst3::com_scrape_types::MakeHeader;
use vst3::{Class, ComWrapper, Steinberg::*};
use crate::util::{copy_cstring, copy_wstring};
use crate::wrapper::PluginConfig;
pub struct Factory<C> {
config: &'static PluginConfig,
_marker: PhantomData<C>,
}
impl<C> Factory<C> {
pub const fn new(config: &'static PluginConfig) -> Self {
Self {
config,
_marker: PhantomData,
}
}
}
pub trait ComponentFactory: Class {
fn create(config: &'static PluginConfig) -> Self;
}
impl<C> Class for Factory<C>
where
C: ComponentFactory + 'static,
C::Interfaces: MakeHeader<C, ComWrapper<C>>,
{
type Interfaces = (IPluginFactory3,);
}
impl<C> IPluginFactoryTrait for Factory<C>
where
C: ComponentFactory + 'static,
C::Interfaces: MakeHeader<C, ComWrapper<C>>,
{
unsafe fn getFactoryInfo(&self, info: *mut PFactoryInfo) -> tresult {
if info.is_null() {
return kInvalidArgument;
}
let info = &mut *info;
copy_cstring(self.config.vendor, &mut info.vendor);
copy_cstring(self.config.url, &mut info.url);
copy_cstring(self.config.email, &mut info.email);
info.flags = PFactoryInfo_::FactoryFlags_::kUnicode as int32;
kResultOk
}
unsafe fn countClasses(&self) -> i32 {
if self.config.has_controller() {
2
} else {
1
}
}
unsafe fn getClassInfo(&self, index: i32, info: *mut PClassInfo) -> tresult {
if info.is_null() {
return kInvalidArgument;
}
match index {
0 => {
let info = &mut *info;
info.cid = self.config.component_uid;
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Audio Module Class", &mut info.category);
copy_cstring(self.config.name, &mut info.name);
kResultOk
}
1 if self.config.has_controller() => {
let info = &mut *info;
info.cid = self.config.controller_uid.unwrap();
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Component Controller Class", &mut info.category);
copy_cstring(self.config.name, &mut info.name);
kResultOk
}
_ => kInvalidArgument,
}
}
unsafe fn createInstance(
&self,
cid: FIDString,
iid: FIDString,
obj: *mut *mut c_void,
) -> tresult {
if cid.is_null() || iid.is_null() || obj.is_null() {
return kInvalidArgument;
}
let requested_cid = &*(cid as *const TUID);
if *requested_cid != self.config.component_uid {
if let Some(controller_uid) = self.config.controller_uid {
if *requested_cid != controller_uid {
return kInvalidArgument;
}
} else {
return kInvalidArgument;
}
}
let component = ComWrapper::new(C::create(self.config));
let unknown = component.as_com_ref::<FUnknown>().unwrap();
let ptr = unknown.as_ptr();
((*(*ptr).vtbl).queryInterface)(ptr, iid as *const TUID, obj)
}
}
impl<C> IPluginFactory2Trait for Factory<C>
where
C: ComponentFactory + 'static,
C::Interfaces: MakeHeader<C, ComWrapper<C>>,
{
unsafe fn getClassInfo2(&self, index: i32, info: *mut PClassInfo2) -> tresult {
if info.is_null() {
return kInvalidArgument;
}
match index {
0 => {
let info = &mut *info;
info.cid = self.config.component_uid;
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Audio Module Class", &mut info.category);
copy_cstring(self.config.name, &mut info.name);
info.classFlags = 0;
copy_cstring(self.config.sub_categories, &mut info.subCategories);
copy_cstring(self.config.vendor, &mut info.vendor);
copy_cstring(self.config.version, &mut info.version);
copy_cstring("VST 3.8.0", &mut info.sdkVersion);
kResultOk
}
1 if self.config.has_controller() => {
let info = &mut *info;
info.cid = self.config.controller_uid.unwrap();
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Component Controller Class", &mut info.category);
copy_cstring(self.config.name, &mut info.name);
info.classFlags = 1; copy_cstring("", &mut info.subCategories);
copy_cstring(self.config.vendor, &mut info.vendor);
copy_cstring(self.config.version, &mut info.version);
copy_cstring("VST 3.8.0", &mut info.sdkVersion);
kResultOk
}
_ => kInvalidArgument,
}
}
}
impl<C> IPluginFactory3Trait for Factory<C>
where
C: ComponentFactory + 'static,
C::Interfaces: MakeHeader<C, ComWrapper<C>>,
{
unsafe fn getClassInfoUnicode(&self, index: i32, info: *mut PClassInfoW) -> tresult {
if info.is_null() {
return kInvalidArgument;
}
match index {
0 => {
let info = &mut *info;
info.cid = self.config.component_uid;
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Audio Module Class", &mut info.category);
copy_wstring(self.config.name, &mut info.name);
info.classFlags = 0;
copy_cstring(self.config.sub_categories, &mut info.subCategories);
copy_wstring(self.config.vendor, &mut info.vendor);
copy_wstring(self.config.version, &mut info.version);
copy_wstring("VST 3.8.0", &mut info.sdkVersion);
kResultOk
}
1 if self.config.has_controller() => {
let info = &mut *info;
info.cid = self.config.controller_uid.unwrap();
info.cardinality = PClassInfo_::ClassCardinality_::kManyInstances as int32;
copy_cstring("Component Controller Class", &mut info.category);
copy_wstring(self.config.name, &mut info.name);
info.classFlags = 1; copy_cstring("", &mut info.subCategories);
copy_wstring(self.config.vendor, &mut info.vendor);
copy_wstring(self.config.version, &mut info.version);
copy_wstring("VST 3.8.0", &mut info.sdkVersion);
kResultOk
}
_ => kInvalidArgument,
}
}
unsafe fn setHostContext(&self, _context: *mut FUnknown) -> tresult {
kResultOk
}
}