procmeta_core/
expr.rs

1use std::collections::HashSet;
2
3use proc_macro2::Span;
4use syn::{
5    spanned::Spanned, Error, Expr, Ident, Lit, LitBool, LitFloat, LitInt, LitStr, Path, Type,
6    TypePath,
7};
8
9pub trait FromMetaExpr: Sized {
10    fn try_from_expr(expr: Expr) -> syn::Result<Self>;
11}
12
13impl FromMetaExpr for Expr {
14    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
15        Ok(expr)
16    }
17}
18
19impl FromMetaExpr for Lit {
20    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
21        if let Expr::Lit(lit) = expr {
22            return Ok(lit.lit);
23        }
24        Err(Error::new(expr.span(), "expected literal"))
25    }
26}
27
28impl FromMetaExpr for LitStr {
29    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
30        if let Expr::Lit(lit) = &expr {
31            let lit = lit.lit.clone();
32            if let Lit::Str(lit) = lit {
33                return Ok(lit);
34            }
35        }
36        Err(Error::new(expr.span(), "expected litteral str"))
37    }
38}
39
40impl FromMetaExpr for LitInt {
41    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
42        if let Expr::Lit(lit) = &expr {
43            let lit = lit.lit.clone();
44            if let Lit::Int(lit) = lit {
45                return Ok(lit);
46            }
47        }
48        Err(Error::new(expr.span(), "expected litteral int"))
49    }
50}
51
52impl FromMetaExpr for LitBool {
53    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
54        if let Expr::Lit(lit) = &expr {
55            let lit = lit.lit.clone();
56            if let Lit::Bool(lit) = lit {
57                return Ok(lit);
58            }
59        }
60        Err(Error::new(expr.span(), "expected litteral bool"))
61    }
62}
63impl FromMetaExpr for LitFloat {
64    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
65        if let Expr::Lit(lit) = &expr {
66            let lit = lit.lit.clone();
67            if let Lit::Float(lit) = lit {
68                return Ok(lit);
69            }
70        }
71        Err(Error::new(expr.span(), "expected litteral float"))
72    }
73}
74
75impl FromMetaExpr for bool {
76    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
77        let lit = LitBool::try_from_expr(expr)?;
78        Ok(lit.value)
79    }
80}
81
82impl FromMetaExpr for f64 {
83    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
84        let lit = LitFloat::try_from_expr(expr)?;
85        lit.base10_parse::<f64>()
86    }
87}
88
89impl FromMetaExpr for i64 {
90    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
91        let lit = LitInt::try_from_expr(expr)?;
92        lit.base10_parse::<i64>()
93    }
94}
95
96impl FromMetaExpr for u64 {
97    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
98        let lit = LitInt::try_from_expr(expr)?;
99        lit.base10_parse::<u64>()
100    }
101}
102
103impl FromMetaExpr for String {
104    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
105        let lit = LitStr::try_from_expr(expr)?;
106        Ok(lit.value())
107    }
108}
109
110impl<T: FromMetaExpr> FromMetaExpr for Option<T> {
111    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
112        let result = T::try_from_expr(expr)?;
113        Ok(Some(result))
114    }
115}
116
117impl FromMetaExpr for Type {
118    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
119        if let Expr::Path(ty) = expr {
120            return Ok(Type::Path(TypePath {
121                qself: ty.qself,
122                path: ty.path,
123            }));
124        }
125        Err(Error::new(expr.span(), "expected type"))
126    }
127}
128
129impl FromMetaExpr for Ident {
130    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
131        if let Expr::Path(path) = expr {
132            let ident = path.path.require_ident()?;
133            return Ok(ident.clone());
134        }
135        Err(Error::new(expr.span(), "expected ident"))
136    }
137}
138
139impl FromMetaExpr for Path {
140    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
141        if let Expr::Path(path) = expr {
142            return Ok(path.path);
143        }
144        Err(Error::new(expr.span(), "expected path"))
145    }
146}
147
148impl<T: FromMetaExpr> FromMetaExpr for Vec<T> {
149    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
150        let mut result = vec![];
151        match expr {
152            Expr::Array(expr) => {
153                for expr in expr.elems {
154                    let item: T = T::try_from_expr(expr)?;
155                    result.push(item);
156                }
157            }
158            _ => {
159                return Err(Error::new(
160                    Span::call_site(),
161                    "标签输入格式错误,实例: tags = [\"abc\"]",
162                ))
163            }
164        }
165        Ok(result)
166    }
167}
168
169impl<T: FromMetaExpr + Eq + std::hash::Hash> FromMetaExpr for HashSet<T> {
170    fn try_from_expr(expr: Expr) -> syn::Result<Self> {
171        let mut result = HashSet::new();
172        match expr {
173            Expr::Array(expr) => {
174                for expr in expr.elems {
175                    let item: T = T::try_from_expr(expr)?;
176                    result.insert(item);
177                }
178            }
179            _ => {
180                return Err(Error::new(
181                    Span::call_site(),
182                    "标签输入格式错误,实例: tags = [\"abc\"]",
183                ))
184            }
185        }
186        Ok(result)
187    }
188}