mod_template_macros 0.3.0

Creating macros that define modules from template modules
Documentation
use std::collections::HashSet;

pub struct AttributeSubstitutionDeclaration {
    target_name_ident: syn::Ident,
}

impl AttributeSubstitutionDeclaration {
    pub fn target_name_ident(&self) -> &syn::Ident {
        &self.target_name_ident
    }
}

pub fn parse(input: syn::parse::ParseStream) -> syn::Result<Vec<AttributeSubstitutionDeclaration>> {
    fn parse_param(
        input: syn::parse::ParseStream,
    ) -> syn::Result<AttributeSubstitutionDeclaration> {
        let target_name_ident: syn::Ident = input.parse()?;

        Ok(AttributeSubstitutionDeclaration { target_name_ident })
    }

    let vec: Vec<_> = {
        let content;
        syn::parenthesized!(content in input);
        content
            .parse_terminated(parse_param, syn::Token![,])?
            .into_iter()
            .collect()
    };

    {
        let mut previous_names = HashSet::new();
        for AttributeSubstitutionDeclaration { target_name_ident } in &vec {
            let target_name = target_name_ident.to_string();
            if previous_names.contains(&target_name) {
                return Err(syn::Error::new(
                    target_name_ident.span(),
                    "duplicate target name",
                ));
            }
            previous_names.insert(target_name);
        }
    }

    Ok(vec)
}

#[cfg(test)]
pub(crate) mod tests {
    use super::AttributeSubstitutionDeclaration;

    #[derive(Debug, PartialEq, Eq, typed_builder::TypedBuilder)]
    pub struct AttributeSubstitutionDeclarationForTest {
        target_name: String,
    }
    impl From<AttributeSubstitutionDeclaration> for AttributeSubstitutionDeclarationForTest {
        fn from(value: AttributeSubstitutionDeclaration) -> Self {
            let AttributeSubstitutionDeclaration { target_name_ident } = value;

            Self {
                target_name: target_name_ident.to_string(),
            }
        }
    }
}