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,
28 node::{Def, HasDef, 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]
51pub fn request_execution(
52 args: proc_macro::TokenStream,
53 input: proc_macro::TokenStream,
54) -> proc_macro::TokenStream {
55 request_execution::expand_request_execution(args.into(), input.into())
56 .unwrap_or_else(syn::Error::into_compile_error)
57 .into()
58}
59
60#[proc_macro_attribute]
69pub fn test(
70 args: proc_macro::TokenStream,
71 input: proc_macro::TokenStream,
72) -> proc_macro::TokenStream {
73 request_execution::expand_test(args.into(), input.into())
74 .unwrap_or_else(syn::Error::into_compile_error)
75 .into()
76}
77
78#[proc_macro_derive(Deref)]
80pub fn derive_deref(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
81 helper_deref::derive_deref(input.into()).into()
82}
83
84#[proc_macro_derive(DerefMut)]
86pub fn derive_deref_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
87 helper_deref::derive_deref_mut(input.into()).into()
88}
89
90mod prelude {
99 pub use crate::authoring_types::{Cardinality, Primitive};
100 pub use crate::{
101 crate_path::CratePaths,
102 r#gen::{Imp, Implementor},
103 helper::{quote_one, quote_option, quote_slice, to_path, to_str_lit},
104 node::*,
105 trait_kind::{
106 ApplicationTypeKind, TraitBuilder, TraitKind, TraitSet, application_type_trait_set,
107 generated_node_trait_set,
108 },
109 types::TraitStrategy,
110 };
111
112 pub const MAX_FIELD_NAME_LEN: usize = 64;
113
114 pub use darling::{Error as DarlingError, FromMeta};
116 pub use proc_macro2::{Span, TokenStream};
117 pub use quote::{ToTokens, format_ident, quote};
118 pub use serde::Deserialize;
119 pub use syn::{Ident, ItemStruct, LitStr, Path};
120}
121
122macro_rules! macro_node {
127 ($fn_name:ident, $node_type:ty $(, $configure:expr)?) => {
128 #[proc_macro_attribute]
129 pub fn $fn_name(
130 args: proc_macro::TokenStream,
131 input: proc_macro::TokenStream,
132 ) -> proc_macro::TokenStream {
133 match NestedMeta::parse_meta_list(args.into()) {
134 Ok(mut args) => {
135 let crate_paths = match CratePathOverrides::extract(&mut args) {
136 Ok(crate_paths) => crate_paths,
137 Err(err) => return err.write_errors().into(),
138 };
139 let item = parse_macro_input!(input as ItemStruct);
140
141 if !matches!(item.vis, Visibility::Public(_)) {
143 return proc_macro::TokenStream::from(
144 DarlingError::custom("expected public visibility").write_errors(),
145 );
146 }
147
148 if !matches!(stringify!($fn_name), "validator" | "normalizer")
150 && let Err(error) = Def::validate_declaration(&item) {
151 return error.write_errors().into();
152 }
153
154 let debug = item.attrs.iter().any(|attr| attr.path().is_ident("debug"));
156 let mut node = match <$node_type>::from_list(&args) {
157 Ok(node) => node,
158 Err(err) => return proc_macro::TokenStream::from(err.write_errors()),
159 };
160 let paths = match crate_paths.resolve() {
161 Ok(paths) => paths,
162 Err(err) => return err.write_errors().into(),
163 };
164 node.def = Def::new(item, paths);
165 $(($configure)(&mut node, CratePathOverrides::has_icydb_runtime());)?
166 if let Err(err) = node.validate() {
167 return proc_macro::TokenStream::from(err.write_errors());
168 }
169
170 let fatal_errors = node.fatal_errors();
172 if !fatal_errors.is_empty() {
173 let tokens: proc_macro2::TokenStream = fatal_errors
174 .into_iter()
175 .map(|err| err.to_compile_error())
176 .collect();
177
178 return tokens.into();
179 }
180
181 let q = node.generate_tokens(node.def().paths());
183
184 if debug {
185 quote! { compile_error!(stringify! { #q }); }
186 } else {
187 q
188 }
189 .into()
190 }
191 Err(e) => proc_macro::TokenStream::from(DarlingError::from(e).write_errors()),
192 }
193 }
194 };
195}
196
197macro_node!(canister, node::Canister);
198macro_node!(
199 entity,
200 node::Entity,
201 |entity: &mut node::Entity, has_runtime| entity.emit_runtime_adapters = has_runtime
202);
203macro_node!(enum_, node::Enum);
204macro_node!(list, node::List);
205macro_node!(map, node::Map);
206macro_node!(newtype, node::Newtype);
207macro_node!(
208 record,
209 node::Record,
210 |record: &mut node::Record, has_runtime| record.emit_runtime_references = has_runtime
211);
212macro_node!(normalizer, node::Normalizer);
213macro_node!(set, node::Set);
214macro_node!(store, node::Store);
215macro_node!(tuple, node::Tuple);
216macro_node!(validator, node::Validator);
217
218#[proc_macro_derive(Add)]
220pub fn derive_add(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
221 helper_ops::derive_add(input.into()).into()
222}
223
224#[proc_macro_derive(AddAssign)]
226pub fn derive_add_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
227 helper_ops::derive_add_assign(input.into()).into()
228}
229
230#[proc_macro_derive(Sub)]
232pub fn derive_sub(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
233 helper_ops::derive_sub(input.into()).into()
234}
235
236#[proc_macro_derive(SubAssign)]
238pub fn derive_sub_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
239 helper_ops::derive_sub_assign(input.into()).into()
240}
241
242#[proc_macro_derive(Mul)]
244pub fn derive_mul(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
245 helper_ops::derive_mul(input.into()).into()
246}
247
248#[proc_macro_derive(MulAssign)]
250pub fn derive_mul_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
251 helper_ops::derive_mul_assign(input.into()).into()
252}
253
254#[proc_macro_derive(Div)]
256pub fn derive_div(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
257 helper_ops::derive_div(input.into()).into()
258}
259
260#[proc_macro_derive(DivAssign)]
262pub fn derive_div_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
263 helper_ops::derive_div_assign(input.into()).into()
264}
265
266#[proc_macro_derive(Rem)]
268pub fn derive_rem(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
269 helper_ops::derive_rem(input.into()).into()
270}
271
272#[proc_macro_derive(RemAssign)]
274pub fn derive_rem_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
275 helper_ops::derive_rem_assign(input.into()).into()
276}
277
278#[proc_macro_derive(Neg)]
280pub fn derive_neg(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
281 helper_ops::derive_neg(input.into()).into()
282}
283
284#[proc_macro_derive(Product)]
286pub fn derive_product(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
287 helper_ops::derive_product(input.into()).into()
288}
289
290#[proc_macro_derive(Sum)]
292pub fn derive_sum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
293 helper_ops::derive_sum(input.into()).into()
294}
295
296#[proc_macro_derive(Display)]
298pub fn derive_display(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
299 helper_display::derive_display(input.into()).into()
300}
301
302#[proc_macro_derive(Inner)]
304pub fn derive_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
305 helper_inner::derive_inner(input.into()).into()
306}