pub fn get_field_type(field_type: syn::Type) -> Option { if let syn::Type::Path(path) = field_type { path.path .segments .last() .map(|last_path_segment| last_path_segment.ident.to_owned()) } else { None } } /// Implement the `validate` function for the struct by calling `validate` function on the fields pub fn validate_config(input: syn::DeriveInput) -> Result { let fields = super::helpers::get_struct_fields(input.data) .map_err(|error| syn::Error::new(proc_macro2::Span::call_site(), error))?; let struct_name = input.ident; let function_expansions = fields .into_iter() .flat_map(|field| field.ident.to_owned().zip(get_field_type(field.ty))) .filter_map(|(field_ident, field_type_ident)| { // Check if a field is a leaf field, only String ( connector urls ) is supported for now let field_ident_string = field_ident.to_string(); let is_optional_field = field_type_ident.eq("Option"); let is_secret_field = field_type_ident.eq("Secret"); // Do not call validate if it is an optional field if !is_optional_field && !is_secret_field { let is_leaf_field = field_type_ident.eq("String"); let validate_expansion = if is_leaf_field { quote::quote!(common_utils::fp_utils::when( self.#field_ident.is_empty(), || { Err(ApplicationError::InvalidConfigurationValueError( format!("{} must not be empty for {}", #field_ident_string, parent_field).into(), )) } )?; ) } else { quote::quote!( self.#field_ident.validate(#field_ident_string)?; ) }; Some(validate_expansion) } else { None } }) .collect::>(); let expansion = quote::quote! { impl #struct_name { /// Validates that the configuration provided for the `parent_field` does not contain empty or default values pub fn validate(&self, parent_field: &str) -> Result<(), ApplicationError> { #(#function_expansions)* Ok(()) } } }; Ok(expansion) }