Skip to main content

audio_plugin_bsd/
metadata.rs

1//! Static metadata describing a loaded plugin (name, version, description, ...).
2
3/// Human-readable metadata for an audio plugin.
4///
5/// A plugin exposes this — via an `extern "C"` accessor in the full loader —
6/// so the host can log plugin identity without interpreting plugin internals.
7/// The `abi_version` field records which host ABI the plugin was built
8/// against (see [`crate::abi`]).
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct PluginMetadata {
11    /// Short human-readable name of the plugin (e.g. `"reverb-plate"`).
12    pub name: String,
13    /// Plugin version string (typically semver, e.g. `"0.3.1"`); free-form.
14    pub version: String,
15    /// One-line description of what the plugin does.
16    pub description: String,
17    /// Optional author / vendor string.
18    pub author: Option<String>,
19    /// Encoded ABI version this plugin was built against (see [`crate::abi`]).
20    pub abi_version: u32,
21    /// Optional SPDX licence identifier (e.g. `"MIT"`).
22    pub license: Option<String>,
23}
24
25impl PluginMetadata {
26    /// Construct a [`PluginMetadata`] with the required fields, leaving
27    /// `author` and `license` as `None`.
28    #[must_use]
29    pub fn new(
30        name: impl Into<String>,
31        version: impl Into<String>,
32        description: impl Into<String>,
33        abi_version: u32,
34    ) -> Self {
35        Self {
36            name: name.into(),
37            version: version.into(),
38            description: description.into(),
39            author: None,
40            abi_version,
41            license: None,
42        }
43    }
44
45    /// Builder: set the `author` field.
46    #[must_use]
47    pub fn with_author(mut self, author: impl Into<String>) -> Self {
48        self.author = Some(author.into());
49        self
50    }
51
52    /// Builder: set the `license` field.
53    #[must_use]
54    pub fn with_license(mut self, license: impl Into<String>) -> Self {
55        self.license = Some(license.into());
56        self
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use crate::abi::encode_abi_version;
63
64    use super::PluginMetadata;
65
66    #[test]
67    fn new_sets_required_fields_and_defaults_optionals() {
68        let m = PluginMetadata::new("gain", "0.1.0", "simple gain", encode_abi_version(1, 0));
69        assert_eq!(m.name, "gain");
70        assert_eq!(m.version, "0.1.0");
71        assert_eq!(m.description, "simple gain");
72        assert_eq!(m.author, None);
73        assert_eq!(m.license, None);
74        assert_eq!(m.abi_version, encode_abi_version(1, 0));
75    }
76
77    #[test]
78    fn with_author_sets_author() {
79        let m = PluginMetadata::new("gain", "0.1.0", "gain", 0).with_author("acme-audio");
80        assert_eq!(m.author.as_deref(), Some("acme-audio"));
81    }
82
83    #[test]
84    fn with_license_sets_license() {
85        let m = PluginMetadata::new("gain", "0.1.0", "gain", 0).with_license("MIT");
86        assert_eq!(m.license.as_deref(), Some("MIT"));
87    }
88
89    #[test]
90    fn builders_chain() {
91        let m = PluginMetadata::new("reverb", "1.2.3", "plate reverb", 1)
92            .with_author("alice")
93            .with_license("BSD-2-Clause");
94        assert_eq!(m.name, "reverb");
95        assert_eq!(m.author.as_deref(), Some("alice"));
96        assert_eq!(m.license.as_deref(), Some("BSD-2-Clause"));
97    }
98
99    #[test]
100    fn eq_clone_hold() {
101        let a = PluginMetadata::new("g", "1", "d", 0);
102        assert_eq!(a.clone(), a);
103        let b = PluginMetadata::new("g", "1", "d", 0);
104        assert_eq!(a, b);
105        assert_ne!(a, PluginMetadata::new("g2", "1", "d", 0));
106    }
107
108    #[test]
109    fn debug_includes_fields() {
110        let m = PluginMetadata::new("gain", "0.1", "g", 1);
111        let s = format!("{m:?}");
112        assert!(s.contains("PluginMetadata"));
113        assert!(s.contains("\"gain\""));
114    }
115}