greentic_types/
provider.rs1use alloc::collections::{BTreeMap, BTreeSet};
7use alloc::{format, string::String, vec::Vec};
8
9#[cfg(feature = "schemars")]
10use schemars::JsonSchema;
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13use serde_json::Value;
14
15use crate::{ErrorCode, GResult, GreenticError};
16
17pub const PROVIDER_EXTENSION_ID: &str = "greentic.provider-extension.v1";
19
20#[derive(Clone, Debug, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23#[cfg_attr(feature = "schemars", derive(JsonSchema))]
24pub struct ProviderManifest {
25 pub provider_type: String,
27 #[cfg_attr(
29 feature = "serde",
30 serde(default, skip_serializing_if = "Vec::is_empty")
31 )]
32 pub capabilities: Vec<String>,
33 #[cfg_attr(
35 feature = "serde",
36 serde(default, skip_serializing_if = "Vec::is_empty")
37 )]
38 pub ops: Vec<String>,
39 #[cfg_attr(
41 feature = "serde",
42 serde(default, skip_serializing_if = "Option::is_none")
43 )]
44 pub config_schema_ref: Option<String>,
45 #[cfg_attr(
47 feature = "serde",
48 serde(default, skip_serializing_if = "Option::is_none")
49 )]
50 pub state_schema_ref: Option<String>,
51}
52
53#[derive(Clone, Debug, PartialEq, Eq)]
55#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56#[cfg_attr(feature = "schemars", derive(JsonSchema))]
57pub struct ProviderRuntimeRef {
58 pub component_ref: String,
60 pub export: String,
62 pub world: String,
64}
65
66#[derive(Clone, Debug, PartialEq, Eq)]
68#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
69#[cfg_attr(feature = "schemars", derive(JsonSchema))]
70pub struct ProviderDecl {
71 pub provider_type: String,
73 #[cfg_attr(
75 feature = "serde",
76 serde(default, skip_serializing_if = "Vec::is_empty")
77 )]
78 pub capabilities: Vec<String>,
79 #[cfg_attr(
81 feature = "serde",
82 serde(default, skip_serializing_if = "Vec::is_empty")
83 )]
84 pub ops: Vec<String>,
85 pub config_schema_ref: String,
87 #[cfg_attr(
89 feature = "serde",
90 serde(default, skip_serializing_if = "Option::is_none")
91 )]
92 pub state_schema_ref: Option<String>,
93 pub runtime: ProviderRuntimeRef,
95 #[cfg_attr(
97 feature = "serde",
98 serde(default, skip_serializing_if = "Option::is_none")
99 )]
100 pub docs_ref: Option<String>,
101}
102
103#[derive(Clone, Debug, PartialEq, Eq, Default)]
105#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
106#[cfg_attr(feature = "schemars", derive(JsonSchema))]
107pub struct ProviderExtensionInline {
108 pub providers: Vec<ProviderDecl>,
110 #[cfg_attr(
112 feature = "serde",
113 serde(default, skip_serializing_if = "BTreeMap::is_empty", flatten)
114 )]
115 pub additional_fields: BTreeMap<String, Value>,
116}
117
118impl ProviderExtensionInline {
119 pub fn validate_basic(&self) -> GResult<()> {
121 let mut seen = BTreeSet::new();
122 for provider in &self.providers {
123 if provider.provider_type.is_empty() {
124 return Err(GreenticError::new(
125 ErrorCode::InvalidInput,
126 "ProviderDecl.provider_type must not be empty",
127 ));
128 }
129 if !seen.insert(&provider.provider_type) {
130 return Err(GreenticError::new(
131 ErrorCode::InvalidInput,
132 format!(
133 "duplicate provider_type '{}' in ProviderExtensionInline",
134 provider.provider_type
135 ),
136 ));
137 }
138 if provider.runtime.component_ref.trim().is_empty()
139 || provider.runtime.export.trim().is_empty()
140 || provider.runtime.world.trim().is_empty()
141 {
142 return Err(GreenticError::new(
143 ErrorCode::InvalidInput,
144 format!(
145 "runtime fields must be set for provider '{}'",
146 provider.provider_type
147 ),
148 ));
149 }
150 }
151 Ok(())
152 }
153}