use crate::error::Result;
use std::path::Path;
use vst3::Steinberg::IPluginFactory;
pub trait VstModule: Send {
fn get_factory(&self) -> Result<*mut IPluginFactory>;
#[allow(dead_code)]
fn path(&self) -> &Path;
}
pub trait ModuleLoader {
fn load(path: &Path) -> Result<Box<dyn VstModule>>;
}
pub fn has_objc_conflicts(path: &Path) -> bool {
if let Some(filename) = path.file_name().and_then(|f| f.to_str()) {
let filename_lower = filename.to_lowercase();
if filename_lower.contains("waveshell") || filename_lower.contains("waves") {
log::info!(
"Detected plugin with Objective-C conflicts requiring process isolation: {}",
filename
);
return true;
}
}
false
}
#[cfg(target_os = "macos")]
fn requires_private_namespace(path: &Path) -> bool {
if let Some(filename) = path.file_name().and_then(|f| f.to_str()) {
let filename_lower = filename.to_lowercase();
if filename_lower.contains("ozone") ||
filename_lower.contains("rx") || filename_lower.contains("neutron") || filename_lower.contains("insight")
{
log::info!(
"Detected plugin requiring private namespace for C symbols: {}",
filename
);
return true;
}
}
false
}
pub fn load_module(path: &Path) -> Result<Box<dyn VstModule>> {
#[cfg(target_os = "macos")]
{
if has_objc_conflicts(path) || requires_private_namespace(path) {
log::info!(
"Using private namespace loader for symbol isolation: {}",
path.display()
);
private_namespace::PrivateNamespaceModuleLoader::load(path)
} else {
log::debug!("Using standard CFBundle loader: {}", path.display());
macos::MacOSModuleLoader::load(path)
}
}
#[cfg(target_os = "windows")]
{
windows::WindowsModuleLoader::load(path)
}
#[cfg(target_os = "linux")]
{
linux::LinuxModuleLoader::load(path)
}
}
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "macos")]
pub mod private_namespace;
#[cfg(target_os = "windows")]
pub mod windows;
#[cfg(target_os = "linux")]
pub mod linux;