Skip to content

Commit

Permalink
chore(config): Set up ConfigurableRef for schema functions (#16568)
Browse files Browse the repository at this point in the history
* Reduce visibility of some pub functions, and drop unused

* Set up `struct ConfigurableRef` for config schema functions

The config schema functions currently dispatch which configurable type to use
based on a type parameter to the functions. In order to make this dispatch
dynamic, a new `struct ConfigurableRef` is set up that contains references to
the functions for a given type implementing `trait Configurable`. This is then
used in the schema functions to dispatch their operation, eliminating the type
bound. This will be used by a follow-up change to allow for dynamically
registrable transforms.
  • Loading branch information
bruceg authored Feb 23, 2023
1 parent a9ba2cb commit ba8c096
Show file tree
Hide file tree
Showing 15 changed files with 211 additions and 166 deletions.
6 changes: 3 additions & 3 deletions lib/vector-common/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use derivative::Derivative;
use serde_json::Value;
use vector_config::{
schema::{
apply_metadata, generate_const_string_schema, generate_one_of_schema,
apply_base_metadata, generate_const_string_schema, generate_one_of_schema,
get_or_generate_schema, SchemaGenerator, SchemaObject,
},
Configurable, GenerateError, Metadata, ToValue,
Expand Down Expand Up @@ -117,7 +117,7 @@ impl Configurable for TimeZone {
let mut local_schema = generate_const_string_schema("local".to_string());
let mut local_metadata = Metadata::with_description("System local timezone.");
local_metadata.add_custom_attribute(CustomAttribute::kv("logical_name", "Local"));
apply_metadata::<()>(&mut local_schema, local_metadata);
apply_base_metadata(&mut local_schema, local_metadata);

let mut tz_metadata = Metadata::with_title("A named timezone.");
tz_metadata.set_description(
Expand All @@ -126,7 +126,7 @@ impl Configurable for TimeZone {
[tzdb]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones"#,
);
tz_metadata.add_custom_attribute(CustomAttribute::kv("logical_name", "Named"));
let tz_schema = get_or_generate_schema::<Tz>(gen, Some(tz_metadata))?;
let tz_schema = get_or_generate_schema(&Tz::as_configurable_ref(), gen, Some(tz_metadata))?;

Ok(generate_one_of_schema(&[local_schema, tz_schema]))
}
Expand Down
16 changes: 12 additions & 4 deletions lib/vector-config-macros/src/configurable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ fn build_to_value_fn(_container: &Container<'_>) -> proc_macro2::TokenStream {
fn build_virtual_newtype_schema_fn(virtual_ty: Type) -> proc_macro2::TokenStream {
quote! {
fn generate_schema(schema_gen: &::std::cell::RefCell<::vector_config::schema::SchemaGenerator>) -> std::result::Result<::vector_config::schema::SchemaObject, ::vector_config::GenerateError> {
::vector_config::schema::get_or_generate_schema::<#virtual_ty>(schema_gen, None)
::vector_config::schema::get_or_generate_schema(
&<#virtual_ty as ::vector_config::Configurable>::as_configurable_ref(),
schema_gen,
None,
)
}
}
}
Expand Down Expand Up @@ -172,7 +176,11 @@ fn generate_struct_field(field: &Field<'_>) -> proc_macro2::TokenStream {
let field_schema_ty = get_field_schema_ty(field);

let spanned_generate_schema = quote_spanned! {field.span()=>
::vector_config::schema::get_or_generate_schema::<#field_schema_ty>(schema_gen, Some(#field_metadata_ref))?
::vector_config::schema::get_or_generate_schema(
&<#field_schema_ty as ::vector_config::Configurable>::as_configurable_ref(),
schema_gen,
Some(#field_metadata_ref),
)?
};

quote! {
Expand Down Expand Up @@ -928,7 +936,7 @@ fn generate_enum_variant_apply_metadata(variant: &Variant<'_>) -> proc_macro2::T

quote! {
#variant_metadata
::vector_config::schema::apply_metadata::<()>(&mut subschema, #variant_metadata_ref);
::vector_config::schema::apply_base_metadata(&mut subschema, #variant_metadata_ref);
}
}

Expand All @@ -938,7 +946,7 @@ fn generate_enum_variant_tag_apply_metadata(variant: &Variant<'_>) -> proc_macro

quote! {
#variant_tag_metadata
::vector_config::schema::apply_metadata::<()>(&mut tag_subschema, #variant_tag_metadata_ref);
::vector_config::schema::apply_base_metadata(&mut tag_subschema, #variant_tag_metadata_ref);
}
}

Expand Down
54 changes: 54 additions & 0 deletions lib/vector-config/src/configurable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ where
/// If an error occurs while generating the schema, an error variant will be returned describing
/// the issue.
fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError>;

/// Create a new configurable reference table.
fn as_configurable_ref() -> ConfigurableRef
where
Self: 'static,
{
ConfigurableRef::new::<Self>()
}
}

/// A type that can be converted directly to a `serde_json::Value`. This is used when translating
Expand All @@ -73,3 +81,49 @@ pub trait ToValue {
/// Convert this value into a `serde_json::Value`. Must not fail.
fn to_value(&self) -> Value;
}

/// A pseudo-reference to a type that can be represented in a Vector configuration. This is
/// composed of references to all the class trait functions.
pub struct ConfigurableRef {
// TODO: Turn this into a plain value once this is resolved:
// https://github.com/rust-lang/rust/issues/63084
type_name: fn() -> &'static str,
// TODO: Turn this into a plain value once const trait functions are implemented
// Ref: https://github.com/rust-lang/rfcs/pull/911
referenceable_name: fn() -> Option<&'static str>,
make_metadata: fn() -> Metadata,
validate_metadata: fn(&Metadata) -> Result<(), GenerateError>,
generate_schema: fn(&RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError>,
}

impl ConfigurableRef {
/// Create a new configurable reference table.
pub const fn new<T: Configurable + ?Sized + 'static>() -> Self {
Self {
type_name: std::any::type_name::<T>,
referenceable_name: T::referenceable_name,
make_metadata: T::metadata,
validate_metadata: T::validate_metadata,
generate_schema: T::generate_schema,
}
}

pub(crate) fn type_name(&self) -> &'static str {
(self.type_name)()
}
pub(crate) fn referenceable_name(&self) -> Option<&'static str> {
(self.referenceable_name)()
}
pub(crate) fn make_metadata(&self) -> Metadata {
(self.make_metadata)()
}
pub(crate) fn validate_metadata(&self, metadata: &Metadata) -> Result<(), GenerateError> {
(self.validate_metadata)(metadata)
}
pub(crate) fn generate_schema(
&self,
gen: &RefCell<SchemaGenerator>,
) -> Result<SchemaObject, GenerateError> {
(self.generate_schema)(gen)
}
}
16 changes: 10 additions & 6 deletions lib/vector-config/src/external/indexmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use crate::{

impl<K, V> Configurable for IndexMap<K, V>
where
K: ConfigurableString + ToValue + std::hash::Hash + Eq,
V: Configurable + ToValue,
K: ConfigurableString + ToValue + std::hash::Hash + Eq + 'static,
V: Configurable + ToValue + 'static,
{
fn is_optional() -> bool {
// A hashmap with required fields would be... an object. So if you want that, make a struct
Expand All @@ -34,9 +34,13 @@ where

fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
// Make sure our key type is _truly_ a string schema.
assert_string_schema_for_map::<K, Self>(gen)?;
assert_string_schema_for_map(
&K::as_configurable_ref(),
gen,
std::any::type_name::<Self>(),
)?;

generate_map_schema::<V>(gen)
generate_map_schema(&V::as_configurable_ref(), gen)
}
}

Expand All @@ -56,7 +60,7 @@ where

impl<V> Configurable for IndexSet<V>
where
V: Configurable + ToValue + std::hash::Hash + Eq,
V: Configurable + ToValue + std::hash::Hash + Eq + 'static,
{
fn metadata() -> Metadata {
Metadata::with_transparent(true)
Expand All @@ -68,7 +72,7 @@ where
}

fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
generate_set_schema::<V>(gen)
generate_set_schema(&V::as_configurable_ref(), gen)
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/vector-config/src/external/no_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl Configurable for no_proxy::NoProxy {
fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
// `NoProxy` (de)serializes itself as a vector of strings, without any constraints on the string value itself, so
// we just... do that.
generate_array_schema::<String>(gen)
generate_array_schema(&String::as_configurable_ref(), gen)
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/vector-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ pub use serde_json;

pub mod component;
mod configurable;
pub use self::configurable::{Configurable, ToValue};
pub use self::configurable::{Configurable, ConfigurableRef, ToValue};
mod errors;
pub use self::errors::{BoundDirection, GenerateError};
mod external;
Expand Down
Loading

0 comments on commit ba8c096

Please sign in to comment.