introspect_proc_macros/
lib.rs1#![warn(missing_docs)]
4#![warn(rust_2018_idioms)]
5#![warn(rust_2021_compatibility)]
6#![warn(missing_debug_implementations)]
7#![warn(rustdoc::broken_intra_doc_links)]
8
9use core::panic;
10
11use introspect_core::r#enum::Variant;
12use introspect_core::r#struct::Field;
13use introspect_core::Entity;
14use introspect_core::Enum;
15use introspect_core::Struct;
16use proc_macro2::TokenStream;
17use quote::quote;
18use syn::Item;
19
20#[proc_macro_derive(Introspect)]
22pub fn introspect(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
23 let item = syn::parse_macro_input!(stream as Item);
24
25 match item {
26 Item::Enum(enum_) => parse_item_enum(enum_),
27 Item::Struct(struct_) => parse_item_struct(struct_),
28 _ => {
29 quote! {
30 compile_error!("Introspect can only be derived for `enum`s and `struct`s")
31 }
32 }
33 }
34 .into()
35}
36
37fn parse_item_enum(item: syn::ItemEnum) -> TokenStream {
38 let ident = &item.ident;
39
40 let enum_ = match Enum::try_from(&item) {
41 Ok(enum_) => Entity::Enum(enum_),
42 Err(err) => panic!("error: {err}"),
46 };
47
48 let variants = item
49 .variants
50 .iter()
51 .map(|field| match Variant::try_from(field) {
52 Ok(variant) => variant,
53 Err(err) => panic!("error: {err}"),
57 })
58 .map(introspect_core::Member::Variant)
59 .collect::<Vec<_>>();
60
61 quote! {
62 #[automatically_derived]
63 impl ::introspect::IntrospectedEntity for #ident {
64
65 fn introspected_entity() -> ::introspect::Entity {
66 #enum_
67 }
68 }
69
70 #[automatically_derived]
71 impl ::introspect::IntrospectedMembers for #ident {
72
73 fn introspected_members() -> Vec<::introspect::Member> {
74 vec![
75 #(#variants),*
76 ]
77 }
78 }
79
80 #[automatically_derived]
81 impl ::introspect::Introspected for #ident {}
82 }
83}
84
85fn parse_item_struct(item: syn::ItemStruct) -> TokenStream {
86 let ident = &item.ident;
87
88 let struct_ = match Struct::try_from(&item) {
89 Ok(struct_) => Entity::Struct(struct_),
90 Err(err) => panic!("error: {err}"),
94 };
95
96 let fields = item
97 .fields
98 .iter()
99 .map(|field| match Field::try_from(field) {
100 Ok(field) => field,
101 Err(err) => panic!("error: {err}"),
105 })
106 .map(introspect_core::Member::Field)
107 .collect::<Vec<_>>();
108
109 quote! {
110 #[automatically_derived]
111 impl ::introspect::IntrospectedEntity for #ident {
112
113 fn introspected_entity() -> ::introspect::Entity {
114 #struct_
115 }
116 }
117
118 #[automatically_derived]
119 impl ::introspect::IntrospectedMembers for #ident {
120
121 fn introspected_members() -> Vec<::introspect::Member> {
122 vec![
123 #(#fields),*
124 ]
125 }
126 }
127
128 #[automatically_derived]
129 impl ::introspect::Introspected for #ident {}
130 }
131}