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
use Check;
// #[proc_macro_derive(Check0, attributes(range))]
// pub fn derive_range_checker0(input: TokenStream) -> TokenStream {
// // 使用 syn 将 TokenStream 解析为结构化的语法树
// let input = parse_macro_input!(input);
// // 取出 ident 后续备用
// // 如果我们为 struct Location 派生我们的 Check 宏的话
// // 此处的 ident 就是 Location
// let DeriveInput { ident, .. } = input;
// // 用于后续缓存待检查的条目
// let mut check_list = vec![];
// // part 0: 数据准备
// // 此处声明我们的 Check 派生宏只对结构体做处理
// if let syn::Data::Struct(syn::DataStruct { fields, .. }) = input.data {
// // 取出结构体中每一项进行处理
// for field in fields {
// // 获取 field 的 ident 以备后用
// let ident_item = &field.ident.unwrap();
// let mut ranges = field
// .attrs
// // 遍历所有的附加属性
// .iter()
// .map(|attr| (attr, attr.path.get_ident()))
// .filter(|(_, ident)| ident.is_some())
// .map(|(attr, ident)| (attr, ident.unwrap()))
// // 筛选出所有属性名为 range 的属性
// .filter(|(_, ident)| (*ident).eq("range"))
// // 将其解析为 Range 表达式
// .map(|(attr, _)| attr.parse_args::<syn::ExprRange>())
// // 返回所有解析成功的 Range 表达式
// .filter_map(|attr| attr.ok());
// // 我们实际上可以利用多个 Range 进行组合,但此处我们只考虑至多只有一个 Range 的情况
// // 若没有 Range 我们则不对这个 field 做任何额外操作
// if let Some(range) = ranges.next() {
// // 构造判断语句并将其转换为 TokenStream 并缓存到一个 check_list 中
// // 这里等效于 (-90.0..=90.0).contains(&self.latitude)
// let check_statement = quote! {(#range).contains(&self.#ident_item)};
// check_list.push(check_statement);
// }
// }
// }
// // part 1: impl struct
// // into() 调用是由于 syn 和 quote 直接调用的是 proc-macro2 库中的相应类型
// // proc-macro2 只是单纯的对 proc-macro 标准库的包装
// // 目的是为了绕开 proc-macro 中的类型只能在标注了 proc-macro = true 的 crate 中使用的限制
// quote!(
// // #ident 是 quote 定义的捕获派生宏函数内局部变量的语法
// // 即此处等效于手动实现了 impl Location
// // 另外,更合理的做法应该是定义一个与宏同名的 trait 再 impl
// // 例如:impl Check for #ident
// // 这样可以避免函数重名,不过此处作为基础例子就先省略这一步了
// impl #ident {
// fn check(&self) -> Result<(), ()> {
// #(
// if !(#check_list) {
// return Err(());
// }
// )*
// Ok(())
// }
// }
// )
// .into()
// }