lilv/
plugin.rs

1use crate::instance::Instance;
2use crate::node::{Node, Nodes};
3use crate::port::{FloatRanges, Port};
4use crate::ui::Uis;
5use crate::world::Life;
6use lilv_sys as lib;
7use lv2_raw::LV2Feature;
8use std::borrow::Borrow;
9use std::convert::TryFrom;
10use std::fmt::Debug;
11use std::ptr::NonNull;
12use std::sync::Arc;
13
14unsafe impl Send for Plugin {}
15unsafe impl Sync for Plugin {}
16
17/// Can be used to instantiave LV2 plugins.
18#[derive(Clone)]
19pub struct Plugin {
20    pub(crate) inner: NonNull<lib::LilvPlugin>,
21    pub(crate) life: Arc<Life>,
22}
23
24impl Plugin {
25    /// Returns true if the plugin is valid. If the world was created with
26    /// `World::load_all`, then this is not necessary. Only valid plugins will
27    /// have been loaded.
28    #[must_use]
29    pub fn verify(&self) -> bool {
30        let _life = self.life.inner.lock();
31        let plugin = self.inner.as_ptr();
32        unsafe { lib::lilv_plugin_verify(plugin) }
33    }
34
35    /// The uri of the plugin.
36    /// # Panics
37    /// Panics if the uri could not be obtained.
38    #[must_use]
39    pub fn uri(&self) -> Node {
40        let _life = self.life.inner.lock();
41        let plugin = self.inner.as_ptr();
42        let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_uri(plugin) as _ }).unwrap();
43        let world = self.life.clone();
44        Node {
45            inner: ptr,
46            borrowed: true,
47            life: world,
48        }
49    }
50
51    /// The uri of the plugin's bundle.
52    /// # Panics
53    /// Panics if the bundle uri could not be obtained.
54    #[must_use]
55    pub fn bundle_uri(&self) -> Node {
56        let _life = self.life.inner.lock();
57        let plugin = self.inner.as_ptr();
58
59        {
60            let ptr =
61                NonNull::new(unsafe { lib::lilv_plugin_get_bundle_uri(plugin) as _ }).unwrap();
62            let world = self.life.clone();
63            Node {
64                inner: ptr,
65                borrowed: true,
66                life: world,
67            }
68        }
69    }
70
71    /// The uri for the data.
72    #[must_use]
73    pub fn data_uris(&self) -> Nodes {
74        let _life = self.life.inner.lock();
75        let plugin = self.inner.as_ptr();
76
77        Nodes {
78            inner: unsafe { lib::lilv_plugin_get_data_uris(plugin) },
79            life: self.life.clone(),
80        }
81    }
82
83    /// The uri for the library.
84    #[must_use]
85    pub fn library_uri(&self) -> Option<Node> {
86        let _life = self.life.inner.lock();
87        let plugin = self.inner.as_ptr();
88
89        Some({
90            let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_library_uri(plugin) as _ })?;
91            let world = self.life.clone();
92            Node {
93                inner: ptr,
94                borrowed: true,
95                life: world,
96            }
97        })
98    }
99
100    /// The (human readable) name of the plugin.
101    ///
102    /// # Panics
103    /// May panic if `verify()` returns false.
104    #[must_use]
105    pub fn name(&self) -> Node {
106        let _life = self.life.inner.lock();
107        let plugin = self.inner.as_ptr();
108
109        {
110            let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_name(plugin).cast() }).unwrap();
111            let world = self.life.clone();
112            Node {
113                inner: ptr,
114                borrowed: false,
115                life: world,
116            }
117        }
118    }
119
120    /// The class of the plugin.
121    ///
122    /// # Panics
123    /// Panics if the pluginc class could not be found.
124    #[must_use]
125    pub fn class(&self) -> Class {
126        let _life = self.life.inner.lock();
127        let plugin = self.inner.as_ptr();
128
129        {
130            let ptr =
131                NonNull::new(unsafe { lib::lilv_plugin_get_class(plugin) as *mut _ }).unwrap();
132            let world = self.life.clone();
133            Class {
134                inner: ptr,
135                life: world,
136            }
137        }
138    }
139
140    /// The value of the predicate. `Nodes` may be empty if the plugin does not
141    /// have one.
142    #[must_use]
143    pub fn value(&self, predicate: &Node) -> Nodes {
144        let _life = self.life.inner.lock();
145        let plugin = self.inner.as_ptr();
146        let predicate = predicate.inner.as_ptr();
147
148        Nodes {
149            inner: unsafe { lib::lilv_plugin_get_value(plugin, predicate) },
150            life: self.life.clone(),
151        }
152    }
153
154    /// `true` if the plugin supports the feature.
155    #[must_use]
156    pub fn has_feature(&self, feature_uri: &Node) -> bool {
157        let _life = self.life.inner.lock();
158        let plugin = self.inner.as_ptr();
159        let feature_uri = feature_uri.inner.as_ptr();
160
161        unsafe { lib::lilv_plugin_has_feature(plugin, feature_uri) }
162    }
163
164    /// The set of features that are supported.
165    #[must_use]
166    pub fn supported_features(&self) -> Nodes {
167        let _life = self.life.inner.lock();
168        let plugin = self.inner.as_ptr();
169        let inner = unsafe { lib::lilv_plugin_get_supported_features(plugin) };
170        let world = self.life.clone();
171        Nodes { inner, life: world }
172    }
173
174    /// The set of features that are required to instantiate the plugin.
175    #[must_use]
176    pub fn required_features(&self) -> Nodes {
177        let _life = self.life.inner.lock();
178        let plugin = self.inner.as_ptr();
179        let inner = unsafe { lib::lilv_plugin_get_required_features(plugin) };
180        let world = self.life.clone();
181        Nodes { inner, life: world }
182    }
183
184    /// The set of features that are optional to instantiate the plugin.
185    #[must_use]
186    pub fn optional_features(&self) -> Nodes {
187        let _life = self.life.inner.lock();
188        let plugin = self.inner.as_ptr();
189        let inner = unsafe { lib::lilv_plugin_get_optional_features(plugin) };
190        let world = self.life.clone();
191        Nodes { inner, life: world }
192    }
193
194    /// Returns `true` if the plugin has extension data for `uri`.
195    #[must_use]
196    pub fn has_extension_data(&self, uri: &Node) -> bool {
197        let _life = self.life.inner.lock();
198        let plugin = self.inner.as_ptr();
199        let uri = uri.inner.as_ptr();
200
201        unsafe { lib::lilv_plugin_has_extension_data(plugin, uri) }
202    }
203
204    /// Get a sequence of all extension data provided by a plugin.
205    #[must_use]
206    pub fn extension_data(&self) -> Option<Nodes> {
207        let _life = self.life.inner.lock();
208        let plugin = self.inner.as_ptr();
209
210        Some({
211            let inner = unsafe { lib::lilv_plugin_get_extension_data(plugin) };
212            let world = self.life.clone();
213            Nodes { inner, life: world }
214        })
215    }
216
217    /// Returns the number of ports for the plugin.
218    #[must_use]
219    pub fn ports_count(&self) -> usize {
220        let _life = self.life.inner.lock();
221        let plugin = self.inner.as_ptr();
222        unsafe { lib::lilv_plugin_get_num_ports(plugin) as _ }
223    }
224
225    /// Return the ranges for all ports.
226    #[must_use]
227    pub fn port_ranges_float(&self) -> Vec<FloatRanges> {
228        let ports_count = self.ports_count();
229        let mut min = vec![0_f32; ports_count];
230        let mut max = vec![0_f32; ports_count];
231        let mut default = vec![0_f32; ports_count];
232        let plugin = self.inner.as_ptr();
233
234        unsafe {
235            let _life = self.life.inner.lock();
236            lib::lilv_plugin_get_port_ranges_float(
237                plugin,
238                min.as_mut_ptr(),
239                max.as_mut_ptr(),
240                default.as_mut_ptr(),
241            );
242        }
243        (0..ports_count)
244            .map(|i| FloatRanges {
245                min: min[i],
246                max: max[i],
247                default: default[i],
248            })
249            .collect()
250    }
251
252    /// Returns the number of ports that match all the given classes.
253    #[must_use]
254    pub fn num_ports_of_class<I, N>(&self, classes: I) -> usize
255    where
256        I: IntoIterator<Item = N>,
257        N: Borrow<Node>,
258    {
259        let mut classes = classes.into_iter();
260        let classes_ref = &mut classes;
261        (0..self.ports_count())
262            .filter_map(|index| self.port_by_index(index))
263            .filter(|port| classes_ref.all(|cls| port.is_a(cls.borrow())))
264            .count()
265    }
266
267    /// Returns wether or not the latency port can be found.
268    #[must_use]
269    pub fn has_latency(&self) -> bool {
270        let _life = self.life.inner.lock();
271        let plugin = self.inner.as_ptr();
272        unsafe { lib::lilv_plugin_has_latency(plugin) }
273    }
274
275    /// Return the index of the plugin's latency port or `None` if it does not exist.
276    #[must_use]
277    pub fn latency_port_index(&self) -> Option<usize> {
278        if self.has_latency() {
279            let _life = self.life.inner.lock();
280            let plugin = self.inner.as_ptr();
281            Some(unsafe { lib::lilv_plugin_get_latency_port_index(plugin) as _ })
282        } else {
283            None
284        }
285    }
286
287    /// Returns an iterator over all the ports.
288    pub fn iter_ports(&self) -> impl Iterator<Item = Port> {
289        PortsIter {
290            plugin: self.clone(),
291            index: 0,
292        }
293    }
294
295    /// Return the port by index or `None` if it does not exist.
296    #[must_use]
297    pub fn port_by_index(&self, index: usize) -> Option<Port> {
298        let _life = self.life.inner.lock();
299        let plugin = self.inner.as_ptr();
300        let index = u32::try_from(index).ok()?;
301
302        Some({
303            let inner = NonNull::new(unsafe {
304                lib::lilv_plugin_get_port_by_index(plugin, index as _) as _
305            })?;
306            Port {
307                inner,
308                plugin: self.clone(),
309            }
310        })
311    }
312
313    //// Get the port by the symbol.
314    ///
315    ///  Note: This function is slower than `port_by_index`, especially on
316    ///  plugins with a very large number of ports.
317    #[must_use]
318    pub fn port_by_symbol(&self, symbol: &Node) -> Option<Port> {
319        let _life = self.life.inner.lock();
320        let plugin = self.inner.as_ptr();
321        let symbol = symbol.inner.as_ptr();
322
323        Some({
324            let inner =
325                NonNull::new(unsafe { lib::lilv_plugin_get_port_by_symbol(plugin, symbol) as _ })?;
326            Port {
327                inner,
328                plugin: self.clone(),
329            }
330        })
331    }
332
333    /// Get a port on plugin by its lv2:designation.
334    ///
335    /// The designation of a port describes the meaning, assignment, allocation
336    /// or role of the port, e.g. "left channel" or "gain". If found, the port
337    /// with matching `port_class` and designation is be returned, otherwise
338    /// `None` is returned. The `port_class` can be used to distinguish the
339    /// input and output ports for a particular designation. If `port_class` is
340    /// `None`, any port with the given designation will be returned.
341    #[must_use]
342    pub fn port_by_designation(
343        &self,
344        port_class: Option<&Node>,
345        designation: &Node,
346    ) -> Option<Port> {
347        let _life = self.life.inner.lock();
348        let plugin = self.inner.as_ptr();
349        let port_class = port_class.map_or(std::ptr::null(), |n| n.inner.as_ptr());
350        let designation = designation.inner.as_ptr();
351
352        Some({
353            let inner = NonNull::new(unsafe {
354                lib::lilv_plugin_get_port_by_designation(plugin, port_class, designation) as _
355            })?;
356            Port {
357                inner,
358                plugin: self.clone(),
359            }
360        })
361    }
362
363    /// Get the project the plugin is a part of.
364    ///
365    /// More information about the project can be read with `World::find_nodes`.
366    #[must_use]
367    pub fn project(&self) -> Option<Node> {
368        let _life = self.life.inner.lock();
369        let plugin = self.inner.as_ptr();
370
371        Some({
372            let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_project(plugin) })?;
373            let world = self.life.clone();
374            Node {
375                inner: ptr,
376                borrowed: false,
377                life: world,
378            }
379        })
380    }
381
382    /// Returns the author name if present.
383    #[must_use]
384    pub fn author_name(&self) -> Option<Node> {
385        let _life = self.life.inner.lock();
386        let plugin = self.inner.as_ptr();
387
388        Some({
389            let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_author_name(plugin) })?;
390            let world = self.life.clone();
391            Node {
392                inner: ptr,
393                borrowed: false,
394                life: world,
395            }
396        })
397    }
398
399    /// Returns the author email if present.
400    #[must_use]
401    pub fn author_email(&self) -> Option<Node> {
402        let _life = self.life.inner.lock();
403        let plugin = self.inner.as_ptr();
404
405        Some({
406            let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_author_email(plugin) })?;
407            let world = self.life.clone();
408            Node {
409                inner: ptr,
410                borrowed: false,
411                life: world,
412            }
413        })
414    }
415
416    #[must_use]
417    pub fn author_homepage(&self) -> Option<Node> {
418        let _life = self.life.inner.lock();
419        let plugin = self.inner.as_ptr();
420        let ptr = NonNull::new(unsafe { lib::lilv_plugin_get_author_homepage(plugin) })?;
421        let world = self.life.clone();
422
423        Some(Node {
424            inner: ptr,
425            borrowed: false,
426            life: world,
427        })
428    }
429
430    /// `true` if the plugin has been replaced by another plugin.
431    ///
432    /// The plugin will still be usable, but hosts should hide them from their
433    /// user interfaces to prevent users fromusing deprecated plugins.
434    #[must_use]
435    pub fn is_replaced(&self) -> bool {
436        let _life = self.life.inner.lock();
437        let plugin = self.inner.as_ptr();
438        unsafe { lib::lilv_plugin_is_replaced(plugin) }
439    }
440
441    /// Get the resources related to plugin with lv2:appliesTo.
442    ///
443    /// Some plugin-related resources are not linked directly to the plugin with
444    /// rdfs:seeAlso and thus will not be automatically loaded along with the
445    /// plugin data (usually for performance reasons). All such resources of the
446    /// given type related to plugin can be accessed with this function.
447    ///
448    /// If typ is `None`, all such resources will be returned, regardless of
449    /// type.
450    ///
451    /// To actually load the data for each returned resource, use
452    /// `World::load_resource()`.
453    #[must_use]
454    pub fn related(&self, typ: Option<&Node>) -> Option<Nodes> {
455        let _life = self.life.inner.lock();
456        let plugin = self.inner.as_ptr();
457        let plugin_type = typ.map_or(std::ptr::null(), |n| n.inner.as_ptr() as _);
458
459        Some({
460            let inner = unsafe { lib::lilv_plugin_get_related(plugin, plugin_type) };
461            let world = self.life.clone();
462            Nodes { inner, life: world }
463        })
464    }
465
466    /// Get all UIs for plugin.
467    #[must_use]
468    pub fn uis(&self) -> Option<Uis> {
469        let _life = self.life.inner.lock();
470        let plugin = self.inner.as_ptr();
471
472        Some(Uis {
473            inner: NonNull::new(unsafe { lib::lilv_plugin_get_uis(plugin) })?,
474            life: self.life.clone(),
475            plugin: self.clone(),
476        })
477    }
478
479    /// Instantiate a plugin.
480    ///
481    /// # Safety
482    /// Instantiating a plugin calls the plugin's code which itself may be
483    /// unsafe.
484    #[must_use]
485    pub unsafe fn instantiate<'a, FS>(&self, sample_rate: f64, features: FS) -> Option<Instance>
486    where
487        FS: IntoIterator<Item = &'a LV2Feature>,
488    {
489        let _life = self.life.inner.lock();
490        let plugin = self.inner.as_ptr();
491        let features_vec: Vec<*const LV2Feature> = features
492            .into_iter()
493            .map(|f| f as *const LV2Feature)
494            .chain(std::iter::once(std::ptr::null()))
495            .collect();
496        let inner = NonNull::new(lib::lilv_plugin_instantiate(
497            plugin,
498            sample_rate,
499            features_vec.as_ptr(),
500        ))?;
501
502        Some(Instance { inner })
503    }
504}
505
506impl Debug for Plugin {
507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
508        f.debug_struct("Plugin")
509            .field("uri", &self.uri())
510            .field("bundle_uri", &self.bundle_uri())
511            .field("data_uris", &self.data_uris())
512            .field("library_uri", &self.library_uri())
513            .field("class", &self.class())
514            .field("required_features", &self.required_features())
515            .field("optional_features", &self.optional_features())
516            .field("ports_count", &self.ports_count())
517            .field("has_latency", &self.has_latency())
518            .field("project", &self.project())
519            .field("author_name", &self.author_name())
520            .field("author_email", &self.author_email())
521            .field("author_homepage", &self.author_homepage())
522            .field("is_replaced", &self.is_replaced())
523            .finish()
524    }
525}
526
527/// A collection of plugins.
528pub struct Plugins {
529    pub(crate) life: Arc<Life>,
530    pub(crate) ptr: *const lib::LilvPlugins,
531}
532
533impl Plugins {
534    /// An iterable over all the plugins in the world.
535    pub fn iter(&self) -> impl '_ + Iterator<Item = Plugin> {
536        let _life = self.life.inner.lock();
537        PluginsIter {
538            plugins: self,
539            iter: { unsafe { lib::lilv_plugins_begin(self.ptr) } },
540        }
541    }
542
543    /// Get a plugin by its unique identifier.
544    #[must_use]
545    pub fn plugin(&self, uri: &Node) -> Option<Plugin> {
546        let _life = self.life.inner.lock();
547        let uri_ptr = uri.inner.as_ptr();
548        let plugin_ptr: *mut lib::LilvPlugin =
549            unsafe { lib::lilv_plugins_get_by_uri(self.ptr, uri_ptr) as *mut _ };
550        Some(Plugin {
551            life: self.life.clone(),
552            inner: NonNull::new(plugin_ptr)?,
553        })
554    }
555
556    /// The number of plugins loaded.
557    #[must_use]
558    pub fn count(&self) -> usize {
559        let _life = self.life.inner.lock();
560        let size = unsafe { lib::lilv_plugins_size(self.ptr) };
561        size as usize
562    }
563}
564
565impl IntoIterator for Plugins {
566    type Item = Plugin;
567
568    type IntoIter = PluginsIter<Plugins>;
569
570    fn into_iter(self) -> Self::IntoIter {
571        let iter = {
572            let _life = self.life.inner.lock();
573            unsafe { lib::lilv_plugins_begin(self.ptr) }
574        };
575        PluginsIter {
576            plugins: self,
577            iter,
578        }
579    }
580}
581
582/// An iterator over plugins.
583pub struct PluginsIter<PS> {
584    pub(crate) plugins: PS,
585    pub(crate) iter: *mut lib::LilvIter,
586}
587
588impl<PS> Iterator for PluginsIter<PS>
589where
590    PS: Borrow<Plugins>,
591{
592    type Item = Plugin;
593
594    fn next(&mut self) -> Option<Plugin> {
595        let _life = self.plugins.borrow().life.inner.lock();
596        let ptr: *mut lib::LilvPlugin =
597            unsafe { lib::lilv_plugins_get(self.plugins.borrow().ptr, self.iter) } as *mut _;
598        self.iter = unsafe { lib::lilv_plugins_next(self.plugins.borrow().ptr, self.iter) };
599        match NonNull::new(ptr) {
600            Some(ptr) => Some(Plugin {
601                life: self.plugins.borrow().life.clone(),
602                inner: ptr,
603            }),
604            None => None,
605        }
606    }
607}
608
609/// Can be used to instantiave LV2 plugins.
610struct PortsIter {
611    pub(crate) plugin: Plugin,
612    pub(crate) index: usize,
613}
614
615impl Iterator for PortsIter {
616    type Item = Port;
617
618    fn next(&mut self) -> Option<Port> {
619        let index = self.index;
620        self.index += 1;
621        self.plugin.port_by_index(index)
622    }
623}
624
625unsafe impl Send for Class {}
626unsafe impl Sync for Class {}
627
628/// A plugin class.
629///
630/// Examples of this include "Reverb Plugin" and "Instrument Plugin".
631pub struct Class {
632    pub(crate) inner: NonNull<lib::LilvPluginClass>,
633    pub(crate) life: Arc<Life>,
634}
635
636impl Class {
637    /// The label of this plugin class, ie "Oscillators".
638    ///
639    /// # Panics
640    /// Panics if the label could not be obtained.
641    #[must_use]
642    pub fn label(&self) -> Node {
643        let _life = self.life.inner.lock();
644        let inner = self.inner.as_ptr();
645
646        {
647            let ptr =
648                NonNull::new(unsafe { lib::lilv_plugin_class_get_label(inner) as _ }).unwrap();
649            let world = self.life.clone();
650            Node {
651                inner: ptr,
652                borrowed: true,
653                life: world,
654            }
655        }
656    }
657
658    /// The URI for the plugin class.
659    #[must_use]
660    pub fn uri(&self) -> Option<Node> {
661        let _life = self.life.inner.lock();
662        let inner = self.inner.as_ptr();
663
664        {
665            let ptr = NonNull::new(unsafe { lib::lilv_plugin_class_get_uri(inner) as _ })?;
666            let world = self.life.clone();
667            Node {
668                inner: ptr,
669                borrowed: true,
670                life: world,
671            }
672        }
673        .into()
674    }
675
676    /// The URI of the this class' superclass.
677    ///
678    /// For example "Instrument Plugin" belongs to "Generator Plugin".
679    #[must_use]
680    pub fn parent_uri(&self) -> Option<Node> {
681        let _life = self.life.inner.lock();
682        let inner = self.inner.as_ptr();
683
684        Some({
685            let ptr = NonNull::new(unsafe { lib::lilv_plugin_class_get_parent_uri(inner) as _ })?;
686            let world = self.life.clone();
687            Node {
688                inner: ptr,
689                borrowed: true,
690                life: world,
691            }
692        })
693    }
694
695    /// The children classes for this class.
696    ///
697    /// For example, the "Generator Plugin" class has "Constant Plugin",
698    /// "Instrument Plugin", and "Oscillator Plugin".
699    #[must_use]
700    pub fn children(&self) -> Option<Classes> {
701        let _life = self.life.inner.lock();
702        let inner = self.inner.as_ptr();
703        Classes {
704            inner: NonNull::new(unsafe { lib::lilv_plugin_class_get_children(inner) })?,
705            life: self.life.clone(),
706        }
707        .into()
708    }
709}
710
711impl Debug for Class {
712    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
713        f.debug_struct("PluginClass")
714            .field("label", &self.label())
715            .field("uri", &self.uri())
716            .field("parent_uri", &self.parent_uri())
717            .finish()
718    }
719}
720
721/// A collection of plugin classes.
722pub struct Classes {
723    pub(crate) inner: NonNull<lib::LilvPluginClasses>,
724    pub(crate) life: Arc<Life>,
725}
726
727impl Classes {
728    /// An iterable over all the plugin classes in the world.
729    #[must_use]
730    pub fn iter(&self) -> ClassIter {
731        let _life = self.life.inner.lock();
732        ClassIter {
733            classes: self.inner.as_ptr(),
734            iter: unsafe { lib::lilv_plugin_classes_begin(self.inner.as_ptr()) },
735            life: self.life.clone(),
736        }
737    }
738
739    /// The number of plugin classes in the collection.
740    #[must_use]
741    pub fn count(&self) -> usize {
742        let _life = self.life.inner.lock();
743        unsafe { lib::lilv_plugin_classes_size(self.inner.as_ptr()) as _ }
744    }
745
746    /// The plugin class with the given URI or `None` if it does not exist.
747    #[must_use]
748    pub fn get_by_uri(&self, uri: &Node) -> Option<Class> {
749        let _life = self.life.inner.lock();
750        let inner = self.inner.as_ptr();
751        let uri = uri.inner.as_ptr();
752
753        Some({
754            let ptr =
755                NonNull::new(unsafe { lib::lilv_plugin_classes_get_by_uri(inner, uri) as _ })?;
756            let world = self.life.clone();
757            Class {
758                inner: ptr,
759                life: world,
760            }
761        })
762    }
763}
764
765/// An iterator over `Class`.
766pub struct ClassIter {
767    classes: *mut lib::LilvPluginClasses,
768    iter: *mut lib::LilvIter,
769    life: Arc<Life>,
770}
771
772impl Iterator for ClassIter {
773    type Item = Class;
774
775    #[must_use]
776    fn next(&mut self) -> Option<Class> {
777        let _life = self.life.inner.lock();
778        let ptr = unsafe { lib::lilv_plugin_classes_get(self.classes, self.iter) };
779        if ptr.is_null() {
780            None
781        } else {
782            self.iter = unsafe { lib::lilv_plugin_classes_next(self.classes, self.iter) };
783            Some({
784                let ptr = NonNull::new(ptr as _)?;
785                let world = self.life.clone();
786                Class {
787                    inner: ptr,
788                    life: world,
789                }
790            })
791        }
792    }
793}
794
795#[cfg(test)]
796mod tests {
797    use crate::world::World;
798
799    #[test]
800    fn test_plugin_format() {
801        let world = World::new();
802        for plugin in world.plugins() {
803            // Just making sure nothing segfaults.
804            _ = format!("{:?}", plugin);
805        }
806    }
807}