icydb_model_macros/
lib.rs1#![doc = include_str!("../README.md")]
7
8extern crate syn_darling as syn;
9
10mod authoring_types;
11mod case;
12mod crate_path;
13mod r#gen;
14mod helper;
15mod helper_deref;
16mod helper_display;
17mod helper_inner;
18mod helper_newtype;
19mod helper_ops;
20mod imp;
21mod node;
22mod predicate;
23mod trait_kind;
24mod types;
25mod validate;
26
27use crate::{
28 crate_path::{CratePathOverrides, rewrite_generated_paths},
29 node::{Def, ValidateNode},
30};
31use darling::{Error as DarlingError, FromMeta, ast::NestedMeta};
32use quote::quote;
33use syn::{ItemStruct, Visibility, parse_macro_input};
34
35#[proc_macro_derive(Deref)]
37pub fn derive_deref(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
38 helper_deref::derive_deref(input.into()).into()
39}
40
41#[proc_macro_derive(DerefMut)]
43pub fn derive_deref_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
44 helper_deref::derive_deref_mut(input.into()).into()
45}
46
47mod prelude {
56 pub use crate::authoring_types::{Cardinality, Primitive};
57 pub use crate::{
58 r#gen::{Imp, Implementor},
59 helper::{quote_one, quote_option, quote_slice, to_path, to_str_lit},
60 node::*,
61 trait_kind::{TraitBuilder, TraitKind},
62 types::TraitStrategy,
63 };
64
65 pub const MAX_FIELD_NAME_LEN: usize = 64;
66
67 pub use darling::{Error as DarlingError, FromMeta};
69 pub use proc_macro2::{Span, TokenStream};
70 pub use quote::{ToTokens, format_ident, quote};
71 pub use serde::Deserialize;
72 pub use syn::{Ident, ItemStruct, LitStr, Path};
73}
74
75macro_rules! macro_node {
80 ($fn_name:ident, $node_type:ty, $gen_type:path $(, $configure:expr)?) => {
81 #[proc_macro_attribute]
82 pub fn $fn_name(
83 args: proc_macro::TokenStream,
84 input: proc_macro::TokenStream,
85 ) -> proc_macro::TokenStream {
86 match NestedMeta::parse_meta_list(args.into()) {
87 Ok(mut args) => {
88 let crate_paths = match CratePathOverrides::extract(&mut args) {
89 Ok(crate_paths) => crate_paths,
90 Err(err) => return err.write_errors().into(),
91 };
92 let item = parse_macro_input!(input as ItemStruct);
93
94 if !matches!(item.vis, Visibility::Public(_)) {
96 return proc_macro::TokenStream::from(
97 DarlingError::custom("expected public visibility").write_errors(),
98 );
99 }
100
101 let debug = item.attrs.iter().any(|attr| attr.path().is_ident("debug"));
103 let mut node = match <$node_type>::from_list(&args) {
104 Ok(node) => node,
105 Err(err) => return proc_macro::TokenStream::from(err.write_errors()),
106 };
107 node.def = Def::new(item);
108 $(($configure)(&mut node, CratePathOverrides::has_icydb_runtime());)?
109 if let Err(err) = node.validate() {
110 return proc_macro::TokenStream::from(err.write_errors());
111 }
112
113 let fatal_errors = node.fatal_errors();
115 if !fatal_errors.is_empty() {
116 let tokens: proc_macro2::TokenStream = fatal_errors
117 .into_iter()
118 .map(|err| err.to_compile_error())
119 .collect();
120
121 return tokens.into();
122 }
123
124 let generator = $gen_type(&node);
126 let q = match rewrite_generated_paths(quote!(#generator), &crate_paths) {
127 Ok(tokens) => tokens,
128 Err(err) => return err.write_errors().into(),
129 };
130
131 if debug {
132 quote! { compile_error!(stringify! { #q }); }
133 } else {
134 q
135 }
136 .into()
137 }
138 Err(e) => proc_macro::TokenStream::from(DarlingError::from(e).write_errors()),
139 }
140 }
141 };
142}
143
144macro_node!(canister, node::Canister, r#gen::CanisterGen);
145macro_node!(
146 entity,
147 node::Entity,
148 r#gen::EntityGen,
149 |entity: &mut node::Entity, has_runtime| entity.emit_runtime_adapters = has_runtime
150);
151macro_node!(enum_, node::Enum, r#gen::EnumGen);
152macro_node!(list, node::List, r#gen::ListGen);
153macro_node!(map, node::Map, r#gen::MapGen);
154macro_node!(newtype, node::Newtype, r#gen::NewtypeGen);
155macro_node!(record, node::Record, r#gen::RecordGen);
156macro_node!(normalizer, node::Normalizer, r#gen::NormalizerGen);
157macro_node!(set, node::Set, r#gen::SetGen);
158macro_node!(store, node::Store, r#gen::StoreGen);
159macro_node!(tuple, node::Tuple, r#gen::TupleGen);
160macro_node!(validator, node::Validator, r#gen::ValidatorGen);
161
162#[proc_macro_derive(Add)]
164pub fn derive_add(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
165 finish_helper_derive(helper_ops::derive_add(input.into()))
166}
167
168#[proc_macro_derive(AddAssign)]
170pub fn derive_add_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
171 finish_helper_derive(helper_ops::derive_add_assign(input.into()))
172}
173
174#[proc_macro_derive(Sub)]
176pub fn derive_sub(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
177 finish_helper_derive(helper_ops::derive_sub(input.into()))
178}
179
180#[proc_macro_derive(SubAssign)]
182pub fn derive_sub_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
183 finish_helper_derive(helper_ops::derive_sub_assign(input.into()))
184}
185
186#[proc_macro_derive(Mul)]
188pub fn derive_mul(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
189 finish_helper_derive(helper_ops::derive_mul(input.into()))
190}
191
192#[proc_macro_derive(MulAssign)]
194pub fn derive_mul_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
195 finish_helper_derive(helper_ops::derive_mul_assign(input.into()))
196}
197
198#[proc_macro_derive(Div)]
200pub fn derive_div(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
201 finish_helper_derive(helper_ops::derive_div(input.into()))
202}
203
204#[proc_macro_derive(DivAssign)]
206pub fn derive_div_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
207 finish_helper_derive(helper_ops::derive_div_assign(input.into()))
208}
209
210#[proc_macro_derive(Rem)]
212pub fn derive_rem(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
213 finish_helper_derive(helper_ops::derive_rem(input.into()))
214}
215
216#[proc_macro_derive(Sum)]
218pub fn derive_sum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
219 finish_helper_derive(helper_ops::derive_sum(input.into()))
220}
221
222#[proc_macro_derive(Display)]
224pub fn derive_display(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
225 finish_helper_derive(helper_display::derive_display(input.into()))
226}
227
228#[proc_macro_derive(Inner)]
230pub fn derive_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
231 finish_helper_derive(helper_inner::derive_inner(input.into()))
232}
233
234fn finish_helper_derive(tokens: proc_macro2::TokenStream) -> proc_macro::TokenStream {
235 match rewrite_generated_paths(tokens, &CratePathOverrides::default()) {
236 Ok(tokens) => tokens.into(),
237 Err(err) => err.write_errors().into(),
238 }
239}