#![doc = include_str!("../README.md")]
extern crate syn_darling as syn;
mod authoring_types;
mod case;
mod crate_path;
mod r#gen;
mod helper;
mod helper_deref;
mod helper_display;
mod helper_inner;
mod helper_newtype;
mod helper_ops;
mod imp;
mod node;
mod predicate;
mod trait_kind;
mod types;
mod validate;
use crate::{
crate_path::{CratePathOverrides, rewrite_generated_paths},
node::{Def, ValidateNode},
};
use darling::{Error as DarlingError, FromMeta, ast::NestedMeta};
use quote::quote;
use syn::{ItemStruct, Visibility, parse_macro_input};
#[proc_macro_derive(Deref)]
pub fn derive_deref(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
helper_deref::derive_deref(input.into()).into()
}
#[proc_macro_derive(DerefMut)]
pub fn derive_deref_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
helper_deref::derive_deref_mut(input.into()).into()
}
mod prelude {
pub use crate::authoring_types::{Cardinality, Primitive};
pub use crate::{
r#gen::{Imp, Implementor},
helper::{quote_one, quote_option, quote_slice, to_path, to_str_lit},
node::*,
trait_kind::{TraitBuilder, TraitKind},
types::TraitStrategy,
};
pub const MAX_FIELD_NAME_LEN: usize = 64;
pub use darling::{Error as DarlingError, FromMeta};
pub use proc_macro2::{Span, TokenStream};
pub use quote::{ToTokens, format_ident, quote};
pub use serde::Deserialize;
pub use syn::{Ident, ItemStruct, LitStr, Path};
}
macro_rules! macro_node {
($fn_name:ident, $node_type:ty, $gen_type:path $(, $configure:expr)?) => {
#[proc_macro_attribute]
pub fn $fn_name(
args: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
match NestedMeta::parse_meta_list(args.into()) {
Ok(mut args) => {
let crate_paths = match CratePathOverrides::extract(&mut args) {
Ok(crate_paths) => crate_paths,
Err(err) => return err.write_errors().into(),
};
let item = parse_macro_input!(input as ItemStruct);
if !matches!(item.vis, Visibility::Public(_)) {
return proc_macro::TokenStream::from(
DarlingError::custom("expected public visibility").write_errors(),
);
}
let debug = item.attrs.iter().any(|attr| attr.path().is_ident("debug"));
let mut node = match <$node_type>::from_list(&args) {
Ok(node) => node,
Err(err) => return proc_macro::TokenStream::from(err.write_errors()),
};
node.def = Def::new(item);
$(($configure)(&mut node, CratePathOverrides::has_icydb_runtime());)?
if let Err(err) = node.validate() {
return proc_macro::TokenStream::from(err.write_errors());
}
let fatal_errors = node.fatal_errors();
if !fatal_errors.is_empty() {
let tokens: proc_macro2::TokenStream = fatal_errors
.into_iter()
.map(|err| err.to_compile_error())
.collect();
return tokens.into();
}
let generator = $gen_type(&node);
let q = match rewrite_generated_paths(quote!(#generator), &crate_paths) {
Ok(tokens) => tokens,
Err(err) => return err.write_errors().into(),
};
if debug {
quote! { compile_error!(stringify! { #q }); }
} else {
q
}
.into()
}
Err(e) => proc_macro::TokenStream::from(DarlingError::from(e).write_errors()),
}
}
};
}
macro_node!(canister, node::Canister, r#gen::CanisterGen);
macro_node!(
entity,
node::Entity,
r#gen::EntityGen,
|entity: &mut node::Entity, has_runtime| entity.emit_runtime_adapters = has_runtime
);
macro_node!(enum_, node::Enum, r#gen::EnumGen);
macro_node!(list, node::List, r#gen::ListGen);
macro_node!(map, node::Map, r#gen::MapGen);
macro_node!(newtype, node::Newtype, r#gen::NewtypeGen);
macro_node!(record, node::Record, r#gen::RecordGen);
macro_node!(normalizer, node::Normalizer, r#gen::NormalizerGen);
macro_node!(set, node::Set, r#gen::SetGen);
macro_node!(store, node::Store, r#gen::StoreGen);
macro_node!(tuple, node::Tuple, r#gen::TupleGen);
macro_node!(validator, node::Validator, r#gen::ValidatorGen);
#[proc_macro_derive(Add)]
pub fn derive_add(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_add(input.into()))
}
#[proc_macro_derive(AddAssign)]
pub fn derive_add_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_add_assign(input.into()))
}
#[proc_macro_derive(Sub)]
pub fn derive_sub(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_sub(input.into()))
}
#[proc_macro_derive(SubAssign)]
pub fn derive_sub_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_sub_assign(input.into()))
}
#[proc_macro_derive(Mul)]
pub fn derive_mul(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_mul(input.into()))
}
#[proc_macro_derive(MulAssign)]
pub fn derive_mul_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_mul_assign(input.into()))
}
#[proc_macro_derive(Div)]
pub fn derive_div(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_div(input.into()))
}
#[proc_macro_derive(DivAssign)]
pub fn derive_div_assign(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_div_assign(input.into()))
}
#[proc_macro_derive(Rem)]
pub fn derive_rem(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_rem(input.into()))
}
#[proc_macro_derive(Sum)]
pub fn derive_sum(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_ops::derive_sum(input.into()))
}
#[proc_macro_derive(Display)]
pub fn derive_display(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_display::derive_display(input.into()))
}
#[proc_macro_derive(Inner)]
pub fn derive_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
finish_helper_derive(helper_inner::derive_inner(input.into()))
}
fn finish_helper_derive(tokens: proc_macro2::TokenStream) -> proc_macro::TokenStream {
match rewrite_generated_paths(tokens, &CratePathOverrides::default()) {
Ok(tokens) => tokens.into(),
Err(err) => err.write_errors().into(),
}
}