procmeta-core 0.3.5

proc-macro helper
Documentation
use std::collections::HashSet;

use proc_macro2::Span;
use syn::{
    spanned::Spanned, Error, Expr, Ident, Lit, LitBool, LitFloat, LitInt, LitStr, Path, Type,
    TypePath,
};

pub trait FromMetaExpr: Sized {
    fn try_from_expr(expr: Expr) -> syn::Result<Self>;
}

impl FromMetaExpr for Expr {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        Ok(expr)
    }
}

impl FromMetaExpr for Lit {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        if let Expr::Lit(lit) = expr {
            return Ok(lit.lit);
        }
        Err(Error::new(expr.span(), "expected literal"))
    }
}

impl FromMetaExpr for LitStr {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        if let Expr::Lit(lit) = &expr {
            let lit = lit.lit.clone();
            if let Lit::Str(lit) = lit {
                return Ok(lit);
            }
        }
        Err(Error::new(expr.span(), "expected litteral str"))
    }
}

impl FromMetaExpr for LitInt {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        if let Expr::Lit(lit) = &expr {
            let lit = lit.lit.clone();
            if let Lit::Int(lit) = lit {
                return Ok(lit);
            }
        }
        Err(Error::new(expr.span(), "expected litteral int"))
    }
}

impl FromMetaExpr for LitBool {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        if let Expr::Lit(lit) = &expr {
            let lit = lit.lit.clone();
            if let Lit::Bool(lit) = lit {
                return Ok(lit);
            }
        }
        Err(Error::new(expr.span(), "expected litteral bool"))
    }
}
impl FromMetaExpr for LitFloat {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        if let Expr::Lit(lit) = &expr {
            let lit = lit.lit.clone();
            if let Lit::Float(lit) = lit {
                return Ok(lit);
            }
        }
        Err(Error::new(expr.span(), "expected litteral float"))
    }
}

impl FromMetaExpr for bool {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        let lit = LitBool::try_from_expr(expr)?;
        Ok(lit.value)
    }
}

impl FromMetaExpr for f64 {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        let lit = LitFloat::try_from_expr(expr)?;
        lit.base10_parse::<f64>()
    }
}

impl FromMetaExpr for i64 {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        let lit = LitInt::try_from_expr(expr)?;
        lit.base10_parse::<i64>()
    }
}

impl FromMetaExpr for u64 {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        let lit = LitInt::try_from_expr(expr)?;
        lit.base10_parse::<u64>()
    }
}

impl FromMetaExpr for String {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        let lit = LitStr::try_from_expr(expr)?;
        Ok(lit.value())
    }
}

impl<T: FromMetaExpr> FromMetaExpr for Option<T> {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        let result = T::try_from_expr(expr)?;
        Ok(Some(result))
    }
}

impl FromMetaExpr for Type {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        if let Expr::Path(ty) = expr {
            return Ok(Type::Path(TypePath {
                qself: ty.qself,
                path: ty.path,
            }));
        }
        Err(Error::new(expr.span(), "expected type"))
    }
}

impl FromMetaExpr for Ident {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        if let Expr::Path(path) = expr {
            let ident = path.path.require_ident()?;
            return Ok(ident.clone());
        }
        Err(Error::new(expr.span(), "expected ident"))
    }
}

impl FromMetaExpr for Path {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        if let Expr::Path(path) = expr {
            return Ok(path.path);
        }
        Err(Error::new(expr.span(), "expected path"))
    }
}

impl<T: FromMetaExpr> FromMetaExpr for Vec<T> {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        let mut result = vec![];
        match expr {
            Expr::Array(expr) => {
                for expr in expr.elems {
                    let item: T = T::try_from_expr(expr)?;
                    result.push(item);
                }
            }
            _ => {
                return Err(Error::new(
                    Span::call_site(),
                    "标签输入格式错误,实例: tags = [\"abc\"]",
                ))
            }
        }
        Ok(result)
    }
}

impl<T: FromMetaExpr + Eq + std::hash::Hash> FromMetaExpr for HashSet<T> {
    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
        let mut result = HashSet::new();
        match expr {
            Expr::Array(expr) => {
                for expr in expr.elems {
                    let item: T = T::try_from_expr(expr)?;
                    result.insert(item);
                }
            }
            _ => {
                return Err(Error::new(
                    Span::call_site(),
                    "标签输入格式错误,实例: tags = [\"abc\"]",
                ))
            }
        }
        Ok(result)
    }
}