Skip to main content

cordis_include/
options.rs

1//! Serializable entry description — the on-disk shape of one plugin entry.
2
3use crate::node::Node;
4use serde::{Deserialize, Serialize};
5
6/// Whether a boolean is `false` (used by `skip_serializing_if`).
7fn is_false(value: &bool) -> bool {
8    !*value
9}
10
11/// One entry in a config file: a plugin instance plus its group position.
12///
13/// The declared field order is the serialization order (`id` and `name`
14/// first, `config` last), keeping files readable and diff-stable. Entries
15/// with a `group` array are groups; the array order is the child order.
16///
17/// `config` is stored raw: `${{ env.NAME }}` templates stay intact in the
18/// entry tree and are only expanded when the config is handed to a plugin
19/// (see [`crate::Entry::resolved_config`]).
20#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
21pub struct EntryOptions {
22    /// Stable identity of the entry. Missing ids are filled with a random
23    /// 6-character base36 id when the entry enters a tree and persisted on
24    /// the next write-back.
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub id: Option<String>,
27    /// Plugin name used to resolve the plugin implementation.
28    #[serde(default)]
29    pub name: String,
30    /// Whether the entry (and transitively its subtree) is disabled.
31    #[serde(default, skip_serializing_if = "is_false")]
32    pub disabled: bool,
33    /// Names of services that must be active before this entry starts.
34    #[serde(default, skip_serializing_if = "Vec::is_empty")]
35    pub inject: Vec<String>,
36    /// Child entries, in order. Non-empty only for group entries.
37    #[serde(default, skip_serializing_if = "Vec::is_empty")]
38    pub group: Vec<EntryOptions>,
39    /// Raw plugin configuration (templates unexpanded).
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub config: Option<Node>,
42}
43
44impl EntryOptions {
45    /// Create options for a plugin with the given name.
46    pub fn new(name: impl Into<String>) -> Self {
47        Self {
48            name: name.into(),
49            ..Self::default()
50        }
51    }
52
53    /// Set the explicit entry id.
54    pub fn with_id(mut self, id: impl Into<String>) -> Self {
55        self.id = Some(id.into());
56        self
57    }
58
59    /// Set the raw plugin configuration.
60    pub fn with_config(mut self, config: Node) -> Self {
61        self.config = Some(config);
62        self
63    }
64
65    /// Set the child entries (turning this entry into a group).
66    pub fn with_group(mut self, group: Vec<EntryOptions>) -> Self {
67        self.group = group;
68        self
69    }
70
71    /// Mark the entry (and its subtree) as disabled.
72    pub fn with_disabled(mut self, disabled: bool) -> Self {
73        self.disabled = disabled;
74        self
75    }
76
77    /// Declare services that must be active before this entry starts.
78    pub fn with_inject<I, S>(mut self, inject: I) -> Self
79    where
80        I: IntoIterator<Item = S>,
81        S: Into<String>,
82    {
83        self.inject = inject.into_iter().map(Into::into).collect();
84        self
85    }
86}