Skip to main content

bnto_core/metadata/
parameters.rs

1// Parameter schema types — definitions for node parameters.
2//
3// These types describe what parameters a node accepts: their names,
4// types, constraints, UI hints, and conditional visibility rules.
5// Used by both the engine (validation) and the UI (control rendering).
6
7use serde::Serialize;
8
9// --- ParamCondition — Conditional Visibility / Requirement Rules ---
10
11/// A single condition entry: "when `param` has the value `equals`".
12///
13/// Used both standalone (in `ParamCondition::Single`) and as entries
14/// in the `ParamCondition::Any` array.
15#[derive(Debug, Clone, Serialize, PartialEq)]
16#[serde(rename_all = "camelCase")]
17pub struct ParamConditionEntry {
18    /// The name of the parameter to check against.
19    pub param: String,
20    /// The value that triggers visibility/requirement.
21    pub equals: String,
22}
23
24/// Conditional visibility/requirement rule for a parameter.
25///
26/// Uses `#[serde(untagged)]` so Single serializes as a plain object and
27/// Any serializes as an array — no type discriminator field needed.
28#[derive(Debug, Clone, Serialize, PartialEq)]
29#[serde(untagged)]
30pub enum ParamCondition {
31    /// Show/require when a single parameter matches a value.
32    Single(ParamConditionEntry),
33    /// Show/require when ANY of multiple conditions match (OR logic).
34    Any(Vec<ParamConditionEntry>),
35}
36
37// --- OptionEntry — labeled enum choice ---
38
39/// A single choice inside an `Enum` parameter. Carries a machine value
40/// and a human-readable label.
41#[derive(Debug, Clone, Serialize, PartialEq)]
42#[serde(rename_all = "camelCase")]
43pub struct OptionEntry {
44    /// The value stored in config JSON (e.g., `"jpeg"`).
45    pub value: String,
46    /// The label shown in the UI (e.g., `"JPEG"`).
47    pub label: String,
48}
49
50// --- ParameterType ---
51
52/// The type of a node parameter. Determines what UI control to render.
53#[derive(Debug, Clone, Serialize, PartialEq, Default)]
54#[serde(tag = "type", rename_all = "camelCase")]
55pub enum ParameterType {
56    Number,
57    #[default]
58    String,
59    Boolean,
60    /// A choice from a fixed set of options (like a dropdown/select).
61    Enum {
62        options: Vec<OptionEntry>,
63    },
64    Object,
65    /// A file upload parameter (base64-encoded).
66    File {
67        accept: Vec<std::string::String>,
68    },
69}
70
71// --- Constraints ---
72
73/// Optional constraints on a parameter's value (min/max range, required flag).
74#[derive(Debug, Clone, Serialize, PartialEq)]
75#[serde(rename_all = "camelCase")]
76pub struct Constraints {
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub min: Option<f64>,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub max: Option<f64>,
81    pub required: bool,
82}
83
84// --- PresetEntry — quick-pick preset for sliders/numerics ---
85
86/// A labeled preset value offered next to a parameter's control.
87#[derive(Debug, Clone, Serialize, PartialEq)]
88#[serde(rename_all = "camelCase")]
89pub struct PresetEntry {
90    pub value: serde_json::Value,
91    pub label: String,
92}
93
94// --- ParameterDef ---
95
96/// A complete definition of one parameter a node accepts. Provides
97/// everything the engine (validation) and UI (control rendering) need.
98#[derive(Debug, Clone, Serialize, PartialEq)]
99#[serde(rename_all = "camelCase")]
100pub struct ParameterDef {
101    pub name: std::string::String,
102    pub label: std::string::String,
103    pub description: std::string::String,
104    /// Value type — determines what UI control to render.
105    pub param_type: ParameterType,
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub default: Option<serde_json::Value>,
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub constraints: Option<Constraints>,
110
111    // --- UI Metadata Fields ---
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub placeholder: Option<String>,
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub visible_when: Option<ParamCondition>,
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub required_when: Option<ParamCondition>,
118    /// Whether this param can be surfaced in container config panels.
119    #[serde(default = "default_true")]
120    pub surfaceable: bool,
121
122    // --- Presentation Fields (engine-owned schema) ---
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub group: Option<String>,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub suffix: Option<String>,
127    /// Override control identifier (e.g., `"slider"`, `"select"`, `"file"`).
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub control: Option<String>,
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub accept: Option<Vec<String>>,
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub presets: Option<Vec<PresetEntry>>,
134    /// Flip the semantic of a boolean control.
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub inverted: Option<bool>,
137}
138
139/// Serde default for `surfaceable` field during deserialization.
140#[allow(dead_code)]
141fn default_true() -> bool {
142    true
143}
144
145impl Default for ParameterDef {
146    fn default() -> Self {
147        Self {
148            name: String::default(),
149            label: String::default(),
150            description: String::default(),
151            param_type: ParameterType::default(),
152            default: None,
153            constraints: None,
154            placeholder: None,
155            visible_when: None,
156            required_when: None,
157            surfaceable: true,
158            group: None,
159            suffix: None,
160            control: None,
161            accept: None,
162            presets: None,
163            inverted: None,
164        }
165    }
166}