aragog-macros 0.8.0

Macros for Aragog Crate
Documentation
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{spanned::Spanned, Lit, Meta, NestedMeta, Path};

#[derive(Clone)]
pub enum OperationValue {
    Lit(Lit),
    Path(Path),
}

impl OperationValue {
    pub fn parse(nest: &NestedMeta) -> Option<Self> {
        match nest {
            NestedMeta::Meta(meta) => match meta {
                Meta::List(list) => Some(Self::Path(list.path.clone())),
                Meta::NameValue(_) => {
                    emit_error!(
                        nest.span(),
                        "Wrong value, expected literal value or custom type got name value"
                    );
                    None
                }
                Meta::Path(p) => Some(Self::Path(p.clone())),
            },
            NestedMeta::Lit(lit) => Some(Self::Lit(lit.clone())),
        }
    }
}

impl ToTokens for OperationValue {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            OperationValue::Lit(lit) => lit.to_tokens(tokens),
            OperationValue::Path(path) => path.to_tokens(tokens),
        }
    }
}

pub trait ParseOperation: Sized {
    fn parse(path: &Path, lit: Option<OperationValue>, field: Option<String>) -> Option<Self>;

    fn expect_no_field(path: &Path, field: Option<String>) -> Option<()> {
        if field.is_none() {
            Some(())
        } else {
            emit_error!(path.span(), "This operation can't be placed on a field");
            None
        }
    }

    fn expect_field(path: &Path, field: Option<String>) -> Option<String> {
        if field.is_none() {
            emit_error!(path.span(), "This operation must be placed on a field");
        }
        field
    }

    fn expect_literal_value(path: &Path, value: Option<OperationValue>) -> Option<Lit> {
        match Self::expect_value(path, value)? {
            OperationValue::Lit(lit) => Some(lit),
            OperationValue::Path(_) => {
                emit_error!(path.span(), "Operation requires literal value, got a path");
                None
            }
        }
    }

    fn expect_value(path: &Path, value: Option<OperationValue>) -> Option<OperationValue> {
        if value.is_none() {
            emit_error!(path.span(), "Operation requires value");
        }
        value
    }

    fn expect_no_value(value: Option<OperationValue>) -> Option<()> {
        value.map_or(Some(()), |v| {
            emit_error!(v.span(), "Unexpected value");
            None
        })
    }
}