aragog-macros 0.8.0

Macros for Aragog Crate
Documentation
use crate::parse_operation::{OperationValue, ParseOperation};
use proc_macro2::Span;
use syn::{spanned::Spanned, Attribute, Field, Meta, NestedMeta, Path};

pub trait ParseAttribute: Sized {
    type AttributeOperation: ParseOperation;

    fn init(path: &Path, field: Option<&Field>) -> Option<Self>;

    fn field(&self) -> Option<String>;

    fn add_operation(&mut self, span: Span, operation: Self::AttributeOperation);

    fn validate(&self, span: Span) -> bool;

    fn parse_operation(&self, meta: &Meta) -> Option<Self::AttributeOperation> {
        let operation = match meta {
            Meta::NameValue(named_value) => Self::AttributeOperation::parse(
                &named_value.path,
                Some(OperationValue::Lit(named_value.lit.clone())),
                self.field(),
            )?,
            Meta::List(list) => {
                if list.nested.len() > 1 {
                    emit_error!(
                        list.span(),
                        "Wrong format, only one value per operation allowed"
                    );
                    return None;
                }
                let nested_meta = if let Some(m) = list.nested.first() {
                    m
                } else {
                    emit_error!(list.span(), "Wrong format, empty parenthesis");
                    return None;
                };
                let value = OperationValue::parse(nested_meta)?;
                Self::AttributeOperation::parse(&list.path, Some(value), self.field())?
            }
            Meta::Path(path) => Self::AttributeOperation::parse(path, None, self.field())?,
        };
        Some(operation)
    }

    fn parse_attribute(attr: &Attribute, field: Option<&Field>, container: &mut Vec<Self>) {
        let mut cmd = match Self::init(&attr.path, field) {
            None => return,
            Some(c) => c,
        };
        match attr.parse_meta() {
            Ok(meta) => match meta {
                Meta::List(list) => {
                    for nest in list.nested.iter() {
                        match nest {
                            NestedMeta::Meta(meta) => {
                                if let Some(op) = cmd.parse_operation(meta) {
                                    cmd.add_operation(meta.span(), op);
                                }
                            }
                            NestedMeta::Lit(_) => {
                                emit_error!(nest.span(), "Expected meta item, not a Rust Literal");
                            }
                        }
                    }
                    if cmd.validate(list.span()) {
                        container.push(cmd);
                    }
                }
                _ => {
                    emit_error!(meta.span(), "Expected a meta list. Add valid operations");
                }
            },
            Err(error) => emit_error!(
                error.span(),
                format!("Failed to parse attribute: {}", error)
            ),
        }
    }
}