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