vector_config/component/
description.rs1use std::{cell::RefCell, marker::PhantomData};
2
3use snafu::Snafu;
4use toml::Value;
5use vector_config_common::{attributes::CustomAttribute, constants};
6
7use super::{ComponentMarker, GenerateConfig};
8use crate::schema::{SchemaGenerator, SchemaObject};
9use crate::{schema, Configurable, ConfigurableRef, GenerateError, Metadata};
10
11#[derive(Debug, Snafu, Clone, PartialEq, Eq)]
12pub enum ExampleError {
13 #[snafu(display("component '{}' does not exist", component_name))]
14 DoesNotExist { component_name: String },
15}
16
17pub struct ComponentDescription<T: ComponentMarker + Sized> {
19 component_name: &'static str,
20 description: &'static str,
21 label: &'static str,
22 logical_name: &'static str,
23 example_value: fn() -> Value,
24 config: ConfigurableRef,
25 _component_type: PhantomData<T>,
26}
27
28impl<T> ComponentDescription<T>
29where
30 T: ComponentMarker + Sized + 'static,
31 inventory::iter<ComponentDescription<T>>:
32 std::iter::IntoIterator<Item = &'static ComponentDescription<T>>,
33{
34 pub const fn new<C: GenerateConfig + Configurable + 'static>(
43 component_name: &'static str,
44 label: &'static str,
45 logical_name: &'static str,
46 description: &'static str,
47 ) -> Self {
48 ComponentDescription {
49 component_name,
50 description,
51 label,
52 logical_name,
53 example_value: C::generate_config,
54 config: ConfigurableRef::new::<C>(),
55 _component_type: PhantomData,
56 }
57 }
58
59 pub fn example(component_name: &str) -> Result<Value, ExampleError> {
66 inventory::iter::<ComponentDescription<T>>
67 .into_iter()
68 .find(|t| t.component_name == component_name)
69 .ok_or_else(|| ExampleError::DoesNotExist {
70 component_name: component_name.to_owned(),
71 })
72 .map(|t| (t.example_value)())
73 }
74
75 pub fn types() -> Vec<&'static str> {
77 let mut types = Vec::new();
78 for definition in inventory::iter::<ComponentDescription<T>> {
79 types.push(definition.component_name);
80 }
81 types.sort_unstable();
82 types
83 }
84
85 pub fn generate_schemas(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
87 let mut descriptions: Vec<_> = inventory::iter::<Self>.into_iter().collect();
88 descriptions.sort_unstable_by_key(|desc| desc.component_name);
89 let subschemas: Vec<SchemaObject> = descriptions
90 .into_iter()
91 .map(|description| description.generate_schema(gen))
92 .collect::<Result<_, _>>()?;
93 Ok(schema::generate_one_of_schema(&subschemas))
94 }
95
96 fn generate_schema(
98 &self,
99 gen: &RefCell<SchemaGenerator>,
100 ) -> Result<SchemaObject, GenerateError> {
101 let mut tag_subschema =
102 schema::generate_const_string_schema(self.component_name.to_string());
103 let variant_tag_metadata = Metadata::with_description(self.description);
104 schema::apply_base_metadata(&mut tag_subschema, variant_tag_metadata);
105
106 let tag_schema =
107 schema::generate_internal_tagged_variant_schema("type".to_string(), tag_subschema);
108 let flattened_subschemas = vec![tag_schema];
109
110 let mut field_metadata = Metadata::default();
111 field_metadata.set_transparent();
112 let mut subschema =
113 schema::get_or_generate_schema(&self.config, gen, Some(field_metadata))?;
114
115 schema::convert_to_flattened_schema(&mut subschema, flattened_subschemas);
116
117 let mut variant_metadata = Metadata::default();
118 variant_metadata.set_description(self.description);
119 variant_metadata.add_custom_attribute(CustomAttribute::kv(
120 constants::DOCS_META_HUMAN_NAME,
121 self.label,
122 ));
123 variant_metadata
124 .add_custom_attribute(CustomAttribute::kv("logical_name", self.logical_name));
125 schema::apply_base_metadata(&mut subschema, variant_metadata);
126
127 Ok(subschema)
128 }
129}