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}