Description
Configuration comes from parsing attributes. Generally there's 2-3 enums or involved in this process. We need something to hold:
- Info about a single attribute (each field can have many)
- Info about all the attributes for a field
Right now both of these are accomplished with the same struct:
#[derive(Debug, PartialEq, Eq, Default)]
pub(crate) struct CacheDiffAttributes {
/// When present indicates the given string should be used as a name instead of the field name
pub(crate) rename: Option<String>,
/// When present indicates the given path to a function should be used to customize the display of the field value
pub(crate) display: Option<syn::Path>,
/// When `Some` indicates the field should be ignored in the diff comparison
pub(crate) ignore: Option<String>,
}
However this allows representing invalid state. We're already using strum
to guarantee keys are valid, we could split the responsibilities of the above enum into a monolithic "done parsing all attributes" as well as an enum that represents only a single attribute using strum like this:
#[derive(Debug, strum::EnumDiscriminants)]
#[allow(non_camel_case_types)]
/// Allow iterating through keys for error messages
#[strum_discriminants(derive(strum::EnumIter, strum::Display))]
#[strum_discriminants(name(ValidFieldAttributeKeys))]
enum FieldAttribute {
rename(String), // #[cache_diff(rename="...")]
display(syn::Path), // #[cache_diff(display="...")]
ignore(String), // #[cache_diff(ignore)]
}
fn valid_attribute_keys() -> String {
ValidFieldAttributeKeys::iter()
.map(|k| format!("`{k}`"))
.collect::<Vec<String>>()
.join(", ")
}
PR #6 introduces container attributes in addition to field attributes so we should rename things to better represent what they are to distinguish between container and field attributes (which is confusing terminology if you're not familiar with the proc macro nomenclature).