shizen_config/
lib.rs

1//! A configuration crate for VST metadata
2//!
3//! The information configured in the `shizen` table of the `Shizen.toml` VST
4//! manifest is used to populate the necessary information about a VST
5//!
6//! ```toml
7//
8// Doing it like this doesn't show the toml contents with the LSP
9// but it ensures the docs are correct and up to date...
10// #![doc = include_str!("../Shizen.toml")]
11//
12//! [shizen.metadata]
13//! vendor = "Shizen Technologies"
14//! categories = ["effect", "utility", "midi"]
15//! plugin-type = "instrument"
16//!
17//! [shizen.processing]
18//! block-size = 1024
19//! ```
20//!
21//! This configuration will also extract the package information
22//! from the package `Cargo.toml` or the workspace `Cargo.toml`
23//! if the package is part of a workspace
24
25mod enums;
26
27use config::{Config, File, FileFormat};
28use serde::{Deserialize, Serialize};
29use std::env;
30
31pub use crate::enums::{Categories, PluginType};
32
33#[derive(Debug, Default, Serialize, Deserialize)]
34#[serde(rename_all = "kebab-case")]
35#[non_exhaustive]
36pub struct PluginMetadata {
37    /// The `vendor` in the `[shizen.metadata]` table
38    pub vendor: String,
39
40    /// The `categories` list in the `[shizen.metadata]` table
41    pub categories: Option<Vec<Categories>>,
42
43    /// The `plugin_type` in the `[shizen.metadata]` table
44    pub plugin_type: Option<PluginType>,
45}
46
47#[derive(Debug, Serialize, Deserialize)]
48#[serde(rename_all = "kebab-case")]
49#[serde(default)]
50#[non_exhaustive]
51pub struct PluginProcessing {
52    pub block_size: usize,
53}
54
55impl Default for PluginProcessing {
56    fn default() -> Self {
57        Self { block_size: 512 }
58    }
59}
60
61#[derive(Debug, Serialize, Deserialize)]
62#[serde(rename_all = "kebab-case")]
63pub struct Metadata {
64    /// The plugin's metadata table at `[shizen.metadata]`
65    pub metadata: PluginMetadata,
66
67    /// Information on how the VST should process data, at `[shizen.processing]`
68    #[serde(default)]
69    pub processing: PluginProcessing,
70}
71
72#[derive(Debug, Serialize, Deserialize)]
73#[serde(rename_all = "kebab-case")]
74#[serde(default)]
75pub struct PackageInfo {
76    pub name: String,
77    pub version: String,
78    pub description: Option<String>,
79    pub authors: Option<Vec<String>>,
80}
81
82impl Default for PackageInfo {
83    fn default() -> Self {
84        let authors = match env::var("CARGO_PKG_AUTHORS").ok() {
85            Some(authors) if authors.is_empty() => None,
86            Some(authors) => Some(authors.split(':').map(|s| s.trim().to_string()).collect()),
87            None => None,
88        };
89
90        // SAFETY: these env vars always exist
91        Self {
92            name: env::var("CARGO_PKG_NAME").unwrap(),
93            version: env::var("CARGO_PKG_VERSION").unwrap(),
94            description: env::var("CARGO_PKG_DESCRIPTION").ok(),
95            authors,
96        }
97    }
98}
99
100#[derive(Debug, Serialize, Deserialize)]
101#[serde(rename_all = "kebab-case")]
102pub struct ShizenConfig {
103    /// The plugin's metadata table `[shizen]`
104    pub shizen: Metadata,
105    /// Package info extracted from the `Cargo.toml` manifest
106    ///
107    /// This info is not fetched from the actual `Cargo.toml`,
108    /// but is rather fetched from the cargo environment variables,
109    /// to allow for workspaces and getting the fields even if they are
110    /// `fieldname.workspace = true`
111    #[serde(default)]
112    pub package: PackageInfo,
113}
114
115impl ShizenConfig {
116    pub fn new() -> Result<Self, config::ConfigError> {
117        let conf = Config::builder()
118            .add_source(File::new("Shizen.toml", FileFormat::Toml))
119            .build()?
120            .try_deserialize()?;
121
122        Ok(conf)
123    }
124}