icydb_model_macros/
lib.rs1#![doc = include_str!("../README.md")]
7
8mod authoring_types;
9mod case;
10mod crate_path;
11mod r#gen;
12mod helper;
13mod helper_deref;
14mod helper_display;
15mod helper_inner;
16mod helper_newtype;
17mod helper_ops;
18mod imp;
19mod node;
20mod predicate;
21mod request_execution;
22mod trait_kind;
23mod types;
24mod validate;
25
26use crate::{
27 crate_path::{CratePathOverrides, rewrite_generated_paths},
28 node::{Def, ValidateNode},
29};
30use darling::{Error as DarlingError, FromMeta, ast::NestedMeta};
31use quote::quote;
32use syn::{ItemStruct, Visibility, parse_macro_input};
33
34#[proc_macro_attribute]
39pub fn request_execution(
40 args: proc_macro::TokenStream,
41 input: proc_macro::TokenStream,
42) -> proc_macro::TokenStream {
43 request_execution::expand_request_execution(args.into(), input.into())
44 .unwrap_or_else(syn::Error::into_compile_error)
45 .into()
46}
47
48#[proc_macro_attribute]
57pub fn test(
58 args: proc_macro::TokenStream,
59 input: proc_macro::TokenStream,
60) -> proc_macro::TokenStream {
61 request_execution::expand_test(args.into(), input.into())
62 .unwrap_or_else(syn::Error::into_compile_error)
63 .into()
64}
65
66#[proc_macro_derive(Deref)]
68pub fn derive_deref(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
69 helper_deref::derive_deref(input.into()).into()
70}
71
72#[proc_macro_derive(DerefMut)]
74pub fn derive_deref_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
75 helper_deref::derive_deref_mut(input.into()).into()
76}
77
78mod prelude {
87 pub use crate::authoring_types::{Cardinality, Primitive};
88 pub use crate::{
89 r#gen::{Imp, Implementor},
90 helper::{quote_one, quote_option, quote_slice, to_path, to_str_lit},
91 node::*,
92 trait_kind::{
93 ApplicationTypeKind, TraitBuilder, TraitKind, TraitSet, application_type_trait_set,
94 generated_node_trait_set,
95 },
96 types::TraitStrategy,
97 };
98
99 pub const MAX_FIELD_NAME_LEN: usize = 64;
100
101 pub use darling::{Error as DarlingError, FromMeta};
103 pub use proc_macro2::{Span, TokenStream};
104 pub use quote::{ToTokens, format_ident, quote};
105 pub use serde::Deserialize;
106 pub use syn::{Ident, ItemStruct, LitStr, Path};
107}
108
109macro_rules! macro_node {
114 ($fn_name:ident, $node_type:ty, $gen_type:path $(, $configure:expr)?) => {
115 #[proc_macro_attribute]
116 pub fn $fn_name(
117 args: proc_macro::TokenStream,
118 input: proc_macro::TokenStream,
119 ) -> proc_macro::TokenStream {
120 match NestedMeta::parse_meta_list(args.into()) {
121 Ok(mut args) => {
122 let crate_paths = match CratePathOverrides::extract(&mut args) {
123 Ok(crate_paths) => crate_paths,
124 Err(err) => return err.write_errors().into(),
125 };
126 let item = parse_macro_input!(input as ItemStruct);
127
128 if !matches!(item.vis, Visibility::Public(_)) {
130 return proc_macro::TokenStream::from(
131 DarlingError::custom("expected public visibility").write_errors(),
132 );
133 }
134
135 let debug = item.attrs.iter().any(|attr| attr.path().is_ident("debug"));
137 let mut node = match <$node_type>::from_list(&args) {
138 Ok(node) => node,
139 Err(err) => return proc_macro::TokenStream::from(err.write_errors()),
140 };
141 node.def = Def::new(item);
142 $(($configure)(&mut node, CratePathOverrides::has_icydb_runtime());)?
143 if let Err(err) = node.validate() {
144 return proc_macro::TokenStream::from(err.write_errors());
145 }
146
147 let fatal_errors = node.fatal_errors();
149 if !fatal_errors.is_empty() {
150 let tokens: proc_macro2::TokenStream = fatal_errors
151 .into_iter()
152 .map(|err| err.to_compile_error())
153 .collect();
154
155 return tokens.into();
156 }
157
158 let generator = $gen_type(&node);
160 let q = match rewrite_generated_paths(quote!(#generator), &crate_paths) {
161 Ok(tokens) => tokens,
162 Err(err) => return err.write_errors().into(),
163 };
164
165 if debug {
166 quote! { compile_error!(stringify! { #q }); }
167 } else {
168 q
169 }
170 .into()
171 }
172 Err(e) => proc_macro::TokenStream::from(DarlingError::from(e).write_errors()),
173 }
174 }
175 };
176}
177
178macro_node!(canister, node::Canister, r#gen::CanisterGen);
179macro_node!(
180 entity,
181 node::Entity,
182 r#gen::EntityGen,
183 |entity: &mut node::Entity, has_runtime| entity.emit_runtime_adapters = has_runtime
184);
185macro_node!(enum_, node::Enum, r#gen::EnumGen);
186macro_node!(list, node::List, r#gen::ListGen);
187macro_node!(map, node::Map, r#gen::MapGen);
188macro_node!(newtype, node::Newtype, r#gen::NewtypeGen);
189macro_node!(
190 record,
191 node::Record,
192 r#gen::RecordGen,
193 |record: &mut node::Record, has_runtime| record.emit_runtime_references = has_runtime
194);
195macro_node!(normalizer, node::Normalizer, r#gen::NormalizerGen);
196macro_node!(set, node::Set, r#gen::SetGen);
197macro_node!(store, node::Store, r#gen::StoreGen);
198macro_node!(tuple, node::Tuple, r#gen::TupleGen);
199macro_node!(validator, node::Validator, r#gen::ValidatorGen);
200
201#[proc_macro_derive(Add)]
203pub fn derive_add(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
204 finish_helper_derive(helper_ops::derive_add(input.into()))
205}
206
207#[proc_macro_derive(AddAssign)]
209pub fn derive_add_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
210 finish_helper_derive(helper_ops::derive_add_assign(input.into()))
211}
212
213#[proc_macro_derive(Sub)]
215pub fn derive_sub(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
216 finish_helper_derive(helper_ops::derive_sub(input.into()))
217}
218
219#[proc_macro_derive(SubAssign)]
221pub fn derive_sub_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
222 finish_helper_derive(helper_ops::derive_sub_assign(input.into()))
223}
224
225#[proc_macro_derive(Mul)]
227pub fn derive_mul(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
228 finish_helper_derive(helper_ops::derive_mul(input.into()))
229}
230
231#[proc_macro_derive(MulAssign)]
233pub fn derive_mul_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
234 finish_helper_derive(helper_ops::derive_mul_assign(input.into()))
235}
236
237#[proc_macro_derive(Div)]
239pub fn derive_div(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
240 finish_helper_derive(helper_ops::derive_div(input.into()))
241}
242
243#[proc_macro_derive(DivAssign)]
245pub fn derive_div_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
246 finish_helper_derive(helper_ops::derive_div_assign(input.into()))
247}
248
249#[proc_macro_derive(Rem)]
251pub fn derive_rem(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
252 finish_helper_derive(helper_ops::derive_rem(input.into()))
253}
254
255#[proc_macro_derive(RemAssign)]
257pub fn derive_rem_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
258 finish_helper_derive(helper_ops::derive_rem_assign(input.into()))
259}
260
261#[proc_macro_derive(Neg)]
263pub fn derive_neg(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
264 finish_helper_derive(helper_ops::derive_neg(input.into()))
265}
266
267#[proc_macro_derive(Product)]
269pub fn derive_product(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
270 finish_helper_derive(helper_ops::derive_product(input.into()))
271}
272
273#[proc_macro_derive(Sum)]
275pub fn derive_sum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
276 finish_helper_derive(helper_ops::derive_sum(input.into()))
277}
278
279#[proc_macro_derive(Display)]
281pub fn derive_display(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
282 finish_helper_derive(helper_display::derive_display(input.into()))
283}
284
285#[proc_macro_derive(Inner)]
287pub fn derive_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
288 finish_helper_derive(helper_inner::derive_inner(input.into()))
289}
290
291fn finish_helper_derive(tokens: proc_macro2::TokenStream) -> proc_macro::TokenStream {
292 match rewrite_generated_paths(tokens, &CratePathOverrides::default()) {
293 Ok(tokens) => tokens.into(),
294 Err(err) => err.write_errors().into(),
295 }
296}