use crate::instance::Instance;
use crate::node::{Node, Nodes};
use crate::port::{FloatRanges, Port};
use crate::ui::Uis;
use crate::world::Life;
use lilv_sys as lib;
use lv2_raw::LV2Feature;
use std::borrow::Borrow;
use std::convert::TryFrom;
use std::fmt::Debug;
use std::ptr::NonNull;
use std::sync::Arc;
unsafe impl Send for Plugin {}
unsafe impl Sync for Plugin {}
#[derive(Clone)]
pub struct Plugin {
pub(crate) inner: NonNull<lib::LilvPlugin>,
pub(crate) life: Arc<Life>,
}
impl Plugin {
#[must_use]
pub fn verify(&self) -> bool {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
unsafe { lib::lilv_plugin_verify(plugin) }
}
#[must_use]
pub fn uri(&self) -> Node {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_uri(plugin) as _ }).unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: true,
life: world,
}
}
#[must_use]
pub fn bundle_uri(&self) -> Node {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
{
let ptr =
NonNull::new(unsafe { lib::lilv_plugin_get_bundle_uri(plugin) as _ }).unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: true,
life: world,
}
}
}
#[must_use]
pub fn data_uris(&self) -> Nodes {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
Nodes {
inner: unsafe { lib::lilv_plugin_get_data_uris(plugin) },
life: self.life.clone(),
}
}
#[must_use]
pub fn library_uri(&self) -> Option<Node> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
Some({
let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_library_uri(plugin) as _ })?;
let world = self.life.clone();
Node {
inner: ptr,
borrowed: true,
life: world,
}
})
}
#[must_use]
pub fn name(&self) -> Node {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
{
let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_name(plugin).cast() }).unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
}
}
#[must_use]
pub fn class(&self) -> Class {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
{
let ptr =
NonNull::new(unsafe { lib::lilv_plugin_get_class(plugin) as *mut _ }).unwrap();
let world = self.life.clone();
Class {
inner: ptr,
life: world,
}
}
}
#[must_use]
pub fn value(&self, predicate: &Node) -> Nodes {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let predicate = predicate.inner.as_ptr();
Nodes {
inner: unsafe { lib::lilv_plugin_get_value(plugin, predicate) },
life: self.life.clone(),
}
}
#[must_use]
pub fn has_feature(&self, feature_uri: &Node) -> bool {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let feature_uri = feature_uri.inner.as_ptr();
unsafe { lib::lilv_plugin_has_feature(plugin, feature_uri) }
}
#[must_use]
pub fn supported_features(&self) -> Nodes {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let inner = unsafe { lib::lilv_plugin_get_supported_features(plugin) };
let world = self.life.clone();
Nodes { inner, life: world }
}
#[must_use]
pub fn required_features(&self) -> Nodes {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let inner = unsafe { lib::lilv_plugin_get_required_features(plugin) };
let world = self.life.clone();
Nodes { inner, life: world }
}
#[must_use]
pub fn optional_features(&self) -> Nodes {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let inner = unsafe { lib::lilv_plugin_get_optional_features(plugin) };
let world = self.life.clone();
Nodes { inner, life: world }
}
#[must_use]
pub fn has_extension_data(&self, uri: &Node) -> bool {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let uri = uri.inner.as_ptr();
unsafe { lib::lilv_plugin_has_extension_data(plugin, uri) }
}
#[must_use]
pub fn extension_data(&self) -> Option<Nodes> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
Some({
let inner = unsafe { lib::lilv_plugin_get_extension_data(plugin) };
let world = self.life.clone();
Nodes { inner, life: world }
})
}
#[must_use]
pub fn ports_count(&self) -> usize {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
unsafe { lib::lilv_plugin_get_num_ports(plugin) as _ }
}
#[must_use]
pub fn port_ranges_float(&self) -> Vec<FloatRanges> {
let ports_count = self.ports_count();
let mut min = vec![0_f32; ports_count];
let mut max = vec![0_f32; ports_count];
let mut default = vec![0_f32; ports_count];
let plugin = self.inner.as_ptr();
unsafe {
let _life = self.life.inner.lock();
lib::lilv_plugin_get_port_ranges_float(
plugin,
min.as_mut_ptr(),
max.as_mut_ptr(),
default.as_mut_ptr(),
);
}
(0..ports_count)
.map(|i| FloatRanges {
min: min[i],
max: max[i],
default: default[i],
})
.collect()
}
#[must_use]
pub fn num_ports_of_class<I, N>(&self, classes: I) -> usize
where
I: IntoIterator<Item = N>,
N: Borrow<Node>,
{
let mut classes = classes.into_iter();
let classes_ref = &mut classes;
(0..self.ports_count())
.filter_map(|index| self.port_by_index(index))
.filter(|port| classes_ref.all(|cls| port.is_a(cls.borrow())))
.count()
}
#[must_use]
pub fn has_latency(&self) -> bool {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
unsafe { lib::lilv_plugin_has_latency(plugin) }
}
#[must_use]
pub fn latency_port_index(&self) -> Option<usize> {
if self.has_latency() {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
Some(unsafe { lib::lilv_plugin_get_latency_port_index(plugin) as _ })
} else {
None
}
}
pub fn iter_ports(&self) -> impl Iterator<Item = Port> {
PortsIter {
plugin: self.clone(),
index: 0,
}
}
#[must_use]
pub fn port_by_index(&self, index: usize) -> Option<Port> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let index = u32::try_from(index).ok()?;
Some({
let inner = NonNull::new(unsafe {
lib::lilv_plugin_get_port_by_index(plugin, index as _) as _
})?;
Port {
inner,
plugin: self.clone(),
}
})
}
#[must_use]
pub fn port_by_symbol(&self, symbol: &Node) -> Option<Port> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let symbol = symbol.inner.as_ptr();
Some({
let inner =
NonNull::new(unsafe { lib::lilv_plugin_get_port_by_symbol(plugin, symbol) as _ })?;
Port {
inner,
plugin: self.clone(),
}
})
}
#[must_use]
pub fn port_by_designation(
&self,
port_class: Option<&Node>,
designation: &Node,
) -> Option<Port> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let port_class = port_class.map_or(std::ptr::null(), |n| n.inner.as_ptr());
let designation = designation.inner.as_ptr();
Some({
let inner = NonNull::new(unsafe {
lib::lilv_plugin_get_port_by_designation(plugin, port_class, designation) as _
})?;
Port {
inner,
plugin: self.clone(),
}
})
}
#[must_use]
pub fn project(&self) -> Option<Node> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
Some({
let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_project(plugin) })?;
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
})
}
#[must_use]
pub fn author_name(&self) -> Option<Node> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
Some({
let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_author_name(plugin) })?;
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
})
}
#[must_use]
pub fn author_email(&self) -> Option<Node> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
Some({
let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_author_email(plugin) })?;
let world = self.life.clone();
Node {
inner: ptr,
borrowed: false,
life: world,
}
})
}
#[must_use]
pub fn author_homepage(&self) -> Option<Node> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_author_homepage(plugin) })?;
let world = self.life.clone();
Some(Node {
inner: ptr,
borrowed: false,
life: world,
})
}
#[must_use]
pub fn is_replaced(&self) -> bool {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
unsafe { lib::lilv_plugin_is_replaced(plugin) }
}
#[must_use]
pub fn related(&self, typ: Option<&Node>) -> Option<Nodes> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let plugin_type = typ.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
Some({
let inner = unsafe { lib::lilv_plugin_get_related(plugin, plugin_type) };
let world = self.life.clone();
Nodes { inner, life: world }
})
}
#[must_use]
pub fn uis(&self) -> Option<Uis> {
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
Some(Uis {
inner: NonNull::new(unsafe { lib::lilv_plugin_get_uis(plugin) })?,
life: self.life.clone(),
plugin: self.clone(),
})
}
#[must_use]
pub unsafe fn instantiate<'a, FS>(&self, sample_rate: f64, features: FS) -> Option<Instance>
where
FS: IntoIterator<Item = &'a LV2Feature>,
{
let _life = self.life.inner.lock();
let plugin = self.inner.as_ptr();
let features_vec: Vec<*const LV2Feature> = features
.into_iter()
.map(|f| f as *const LV2Feature)
.chain(std::iter::once(std::ptr::null()))
.collect();
let inner = NonNull::new(lib::lilv_plugin_instantiate(
plugin,
sample_rate,
features_vec.as_ptr(),
))?;
Some(Instance { inner })
}
}
impl Debug for Plugin {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Plugin")
.field("uri", &self.uri())
.field("bundle_uri", &self.bundle_uri())
.field("data_uris", &self.data_uris())
.field("library_uri", &self.library_uri())
.field("class", &self.class())
.field("required_features", &self.required_features())
.field("optional_features", &self.optional_features())
.field("ports_count", &self.ports_count())
.field("has_latency", &self.has_latency())
.field("project", &self.project())
.field("author_name", &self.author_name())
.field("author_email", &self.author_email())
.field("author_homepage", &self.author_homepage())
.field("is_replaced", &self.is_replaced())
.finish()
}
}
pub struct Plugins {
pub(crate) life: Arc<Life>,
pub(crate) ptr: *const lib::LilvPlugins,
}
impl Plugins {
pub fn iter(&self) -> impl '_ + Iterator<Item = Plugin> {
let _life = self.life.inner.lock();
PluginsIter {
plugins: self,
iter: { unsafe { lib::lilv_plugins_begin(self.ptr) } },
}
}
#[must_use]
pub fn plugin(&self, uri: &Node) -> Option<Plugin> {
let _life = self.life.inner.lock();
let uri_ptr = uri.inner.as_ptr();
let plugin_ptr: *mut lib::LilvPlugin =
unsafe { lib::lilv_plugins_get_by_uri(self.ptr, uri_ptr) as *mut _ };
Some(Plugin {
life: self.life.clone(),
inner: NonNull::new(plugin_ptr)?,
})
}
#[must_use]
pub fn count(&self) -> usize {
let _life = self.life.inner.lock();
let size = unsafe { lib::lilv_plugins_size(self.ptr) };
size as usize
}
}
impl IntoIterator for Plugins {
type Item = Plugin;
type IntoIter = PluginsIter<Plugins>;
fn into_iter(self) -> Self::IntoIter {
let iter = {
let _life = self.life.inner.lock();
unsafe { lib::lilv_plugins_begin(self.ptr) }
};
PluginsIter {
plugins: self,
iter,
}
}
}
pub struct PluginsIter<PS> {
pub(crate) plugins: PS,
pub(crate) iter: *mut lib::LilvIter,
}
impl<PS> Iterator for PluginsIter<PS>
where
PS: Borrow<Plugins>,
{
type Item = Plugin;
fn next(&mut self) -> Option<Plugin> {
let _life = self.plugins.borrow().life.inner.lock();
let ptr: *mut lib::LilvPlugin =
unsafe { lib::lilv_plugins_get(self.plugins.borrow().ptr, self.iter) } as *mut _;
self.iter = unsafe { lib::lilv_plugins_next(self.plugins.borrow().ptr, self.iter) };
match NonNull::new(ptr) {
Some(ptr) => Some(Plugin {
life: self.plugins.borrow().life.clone(),
inner: ptr,
}),
None => None,
}
}
}
struct PortsIter {
pub(crate) plugin: Plugin,
pub(crate) index: usize,
}
impl Iterator for PortsIter {
type Item = Port;
fn next(&mut self) -> Option<Port> {
let index = self.index;
self.index += 1;
self.plugin.port_by_index(index)
}
}
unsafe impl Send for Class {}
unsafe impl Sync for Class {}
pub struct Class {
pub(crate) inner: NonNull<lib::LilvPluginClass>,
pub(crate) life: Arc<Life>,
}
impl Class {
#[must_use]
pub fn label(&self) -> Node {
let _life = self.life.inner.lock();
let inner = self.inner.as_ptr();
{
let ptr =
NonNull::new(unsafe { lib::lilv_plugin_class_get_label(inner) as _ }).unwrap();
let world = self.life.clone();
Node {
inner: ptr,
borrowed: true,
life: world,
}
}
}
#[must_use]
pub fn uri(&self) -> Option<Node> {
let _life = self.life.inner.lock();
let inner = self.inner.as_ptr();
{
let ptr = NonNull::new(unsafe { lib::lilv_plugin_class_get_uri(inner) as _ })?;
let world = self.life.clone();
Node {
inner: ptr,
borrowed: true,
life: world,
}
}
.into()
}
#[must_use]
pub fn parent_uri(&self) -> Option<Node> {
let _life = self.life.inner.lock();
let inner = self.inner.as_ptr();
Some({
let ptr = NonNull::new(unsafe { lib::lilv_plugin_class_get_parent_uri(inner) as _ })?;
let world = self.life.clone();
Node {
inner: ptr,
borrowed: true,
life: world,
}
})
}
#[must_use]
pub fn children(&self) -> Option<Classes> {
let _life = self.life.inner.lock();
let inner = self.inner.as_ptr();
Classes {
inner: NonNull::new(unsafe { lib::lilv_plugin_class_get_children(inner) })?,
life: self.life.clone(),
}
.into()
}
}
impl Debug for Class {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PluginClass")
.field("label", &self.label())
.field("uri", &self.uri())
.field("parent_uri", &self.parent_uri())
.finish()
}
}
pub struct Classes {
pub(crate) inner: NonNull<lib::LilvPluginClasses>,
pub(crate) life: Arc<Life>,
}
impl Classes {
#[must_use]
pub fn iter(&self) -> ClassIter {
let _life = self.life.inner.lock();
ClassIter {
classes: self.inner.as_ptr(),
iter: unsafe { lib::lilv_plugin_classes_begin(self.inner.as_ptr()) },
life: self.life.clone(),
}
}
#[must_use]
pub fn count(&self) -> usize {
let _life = self.life.inner.lock();
unsafe { lib::lilv_plugin_classes_size(self.inner.as_ptr()) as _ }
}
#[must_use]
pub fn get_by_uri(&self, uri: &Node) -> Option<Class> {
let _life = self.life.inner.lock();
let inner = self.inner.as_ptr();
let uri = uri.inner.as_ptr();
Some({
let ptr =
NonNull::new(unsafe { lib::lilv_plugin_classes_get_by_uri(inner, uri) as _ })?;
let world = self.life.clone();
Class {
inner: ptr,
life: world,
}
})
}
}
pub struct ClassIter {
classes: *mut lib::LilvPluginClasses,
iter: *mut lib::LilvIter,
life: Arc<Life>,
}
impl Iterator for ClassIter {
type Item = Class;
#[must_use]
fn next(&mut self) -> Option<Class> {
let _life = self.life.inner.lock();
let ptr = unsafe { lib::lilv_plugin_classes_get(self.classes, self.iter) };
if ptr.is_null() {
None
} else {
self.iter = unsafe { lib::lilv_plugin_classes_next(self.classes, self.iter) };
Some({
let ptr = NonNull::new(ptr as _)?;
let world = self.life.clone();
Class {
inner: ptr,
life: world,
}
})
}
}
}
#[cfg(test)]
mod tests {
use crate::world::World;
#[test]
fn test_plugin_format() {
let world = World::new();
for plugin in world.plugins() {
format!("{:?}", plugin);
}
}
}