1use proc_macro2::TokenStream;
2use quote::{quote, quote_spanned, ToTokens};
3use syn::{parse_macro_input, spanned::Spanned, DeriveInput, ItemFn, ItemStruct};
4
5mod database;
6mod pushable;
7mod query;
8mod tracked;
9
10type Result<T> = std::result::Result<T, Error>;
11struct Error {
12 span: proc_macro2::Span,
13 message: String,
14}
15
16impl Error {
17 fn new(span: proc_macro2::Span, message: impl ToString) -> Self {
18 Self {
19 span,
20 message: message.to_string(),
21 }
22 }
23}
24
25impl ToTokens for Error {
26 fn to_tokens(&self, tokens: &mut TokenStream) {
27 let message = &self.message;
28 tokens.extend(quote_spanned! { self.span => compile_error!(#message); });
29 }
30}
31
32#[proc_macro_derive(Tracked, attributes(id))]
40pub fn tracked(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
41 let input = parse_macro_input!(item as DeriveInput);
42 match tracked::tracked(input) {
43 Ok(x) => x,
44 Err(e) => quote!(#e),
45 }
46 .into()
47}
48
49#[proc_macro_derive(Interned)]
53pub fn interned(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
54 let input = parse_macro_input!(item as DeriveInput);
55 let ty = input.ident;
56 let (i, t, w) = input.generics.split_for_impl();
57 (quote! {
58 impl #i ::verde::Interned for #ty #t #w {}
59
60 impl #i ::verde::internal::Storable for #ty #t #w {
61 type Storage = ::verde::internal::storage::InternedStorage<Self>;
62
63 fn tracked_storage(store: &Self::Storage) -> Option<&dyn ::verde::internal::storage::ErasedTrackedStorage> {
64 None
65 }
66
67 fn query_storage(store: &Self::Storage) -> Option<&dyn ::verde::internal::storage::ErasedQueryStorage> {
68 None
69 }
70
71 fn pushable_storage(store: &Self::Storage) -> Option<&dyn ::verde::internal::storage::ErasedPushableStorage> {
72 None
73 }
74
75 fn interned_storage(store: &Self::Storage) -> Option<&dyn ::verde::internal::storage::ErasedInternedStorage> {
76 Some(store)
77 }
78 }
79 })
80 .into()
81}
82
83#[proc_macro_derive(Pushable)]
85pub fn pushable(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
86 let input = parse_macro_input!(item as DeriveInput);
87 match pushable::pushable(input) {
88 Ok(x) => x,
89 Err(e) => quote!(#e),
90 }
91 .into()
92}
93
94#[proc_macro_attribute]
100pub fn query(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
101 let attr = TokenStream::from(attr);
102 if !attr.is_empty() {
103 return quote_spanned! { attr.span() => compile_error!("`query` does not take any arguments"); }.into();
104 }
105
106 let input = parse_macro_input!(item as ItemFn);
107 match query::query(input) {
108 Ok(x) => x,
109 Err(e) => quote!(#e),
110 }
111 .into()
112}
113
114#[proc_macro_attribute]
119pub fn storage(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
120 let attr = TokenStream::from(attr);
121 if !attr.is_empty() {
122 return quote_spanned! { attr.span() => compile_error!("`storage` does not take any arguments"); }.into();
123 }
124
125 let input = parse_macro_input!(item as ItemStruct);
126 match database::storage(input) {
127 Ok(x) => x,
128 Err(e) => quote!(#e),
129 }
130 .into()
131}
132
133#[proc_macro_attribute]
137pub fn db(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
138 let attr = TokenStream::from(attr);
139 if !attr.is_empty() {
140 return quote_spanned! { attr.span() => compile_error!("`database` does not take any arguments"); }.into();
141 }
142
143 let input = parse_macro_input!(item as ItemStruct);
144 match database::database(input) {
145 Ok(x) => x,
146 Err(e) => quote!(#e),
147 }
148 .into()
149}