forked from vaind/objectbox-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.rs
172 lines (149 loc) · 5.28 KB
/
lib.rs
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
extern crate maplit;
extern crate objectbox_generator;
extern crate prettyplease;
extern crate proc_macro;
extern crate proc_macro2;
extern crate quote;
extern crate syn;
use objectbox_generator::id;
use proc_macro::TokenStream;
mod debug;
mod entity;
mod path_visitor;
mod property;
use entity::Entity;
use syn::Meta::NameValue;
use syn::{parse_macro_input, AttributeArgs, DeriveInput};
// extension trait for IdUid, reuse structs
trait IdUidMacroHelper {
fn update_from_scan(&mut self, mnv: &syn::MetaNameValue);
fn update_from_nested_metas(&mut self, iter: core::slice::Iter<syn::NestedMeta>);
}
impl IdUidMacroHelper for id::IdUid {
fn update_from_scan(&mut self, mnv: &syn::MetaNameValue) {
if let syn::Lit::Int(li) = &mnv.lit {
let result = li.base10_parse::<u64>();
if let Ok(value) = result {
if let Some(ident) = mnv.path.get_ident() {
let param_name: &str = &ident.to_string();
match param_name {
"uid" => {
if self.uid == 0 {
self.uid = value
}
}
"id" => {
if self.id == 0 {
self.id = value
}
}
_ => {}
}
}
}
}
}
fn update_from_nested_metas(&mut self, iter: core::slice::Iter<syn::NestedMeta>) {
iter.for_each(|nm| match nm {
syn::NestedMeta::Meta(NameValue(mnv)) => {
self.update_from_scan(mnv);
}
_ => {}
});
}
}
fn _entity(input: TokenStream, args: Option<TokenStream>) -> TokenStream {
// print_token_stream("all: ", input.clone());
let struct_clone = input.clone();
// all parse_macro_input! macro have to happen inside a proc_macro_attribute(d) function
let struct_info = parse_macro_input!(struct_clone as DeriveInput);
let mut id = id::IdUid::zero();
if args.is_some() {
let args_unwrapped = args.unwrap();
let attr_args = parse_macro_input!(args_unwrapped as AttributeArgs);
if !attr_args.is_empty() {
id.update_from_nested_metas(attr_args.iter());
}
}
let entity = Entity::from_entity_name_and_fields(id, struct_info);
entity.serialize().write();
// dbg!(entity);
input
.into_iter()
.map(|x| {
if let proc_macro::TokenTree::Group(group) = x {
let new_group = group
.stream()
.into_iter()
.filter(|y| {
match y {
// TODO make sure we only remove _our_ attributes (index, unique etc.)
// TODO replace false and '#' with something more intelligent
proc_macro::TokenTree::Group(_) => false,
proc_macro::TokenTree::Punct(p) => p.as_char() != '#',
_ => true,
}
})
.collect::<TokenStream>();
let pm_group = proc_macro::Group::new(group.delimiter(), new_group);
proc_macro::TokenTree::from(pm_group)
} else {
x
}
})
.collect::<TokenStream>()
}
// This will break with nested sub types.
// The last bit will remove the annotations in the generated code
// because the generated code cannot reference the attributes.
// The result of this is unused imported attributes.
// TODO also remove those unused imports, in the generated code
#[proc_macro_attribute]
pub fn entity(args: TokenStream, input: TokenStream) -> TokenStream {
_entity(input, Some(args))
}
// TODO fix this, also allow for id/uid parameters to entity
// TODO look into [darling](https://crates.io/crates/darling)
// #[proc_macro_derive(OB, attributes(entity))]
// #[proc_macro_derive(OB, attributes(id, unique, index))]
// pub fn derive_ob_entity(input: TokenStream) -> TokenStream {
// _entity(input, None)
// // input
// }
#[proc_macro_attribute]
pub fn sync(_attribute: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// Fields
/// Accepts 'type' parameter
/// Note: indexes are currently not supported for ByteVector, Float or Double
/// See ./objectbox/lib/src/annotations.dart implementation
/// All ids are self-assignable, since there are no write-once / const fields.
#[proc_macro_attribute]
pub fn id(_attribute: TokenStream, input: TokenStream) -> TokenStream {
input
}
#[proc_macro_attribute]
pub fn index(_attribute: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// Accepts 'uid'
#[proc_macro_attribute]
pub fn unique(_attribute: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// Accepts 'to'
#[proc_macro_attribute]
pub fn backlink(_attribute: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// No required params
#[proc_macro_attribute]
pub fn transient(_attribute: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// Accepts 'type' and 'uid'
#[proc_macro_attribute]
pub fn property(_attribute: TokenStream, input: TokenStream) -> TokenStream {
input
}