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 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"))
}
}