1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use syn::{spanned::Spanned, Error, Expr, Lit, LitBool, LitFloat, LitInt, LitStr};

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

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