1#![allow(unused)]
2extern crate proc_macro;
3
4use quote::quote;
5use syn::{
6 Data,
7 DataStruct,
8 Fields,
9 Field,
10 Variant,
11 FieldsUnnamed,
12};
13use generic_core::into::*;
14use generic_core::value::*;
15
16
17
18#[proc_macro_derive(IntoGeneric)]
23pub fn into_generic_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
24 let ast = syn::parse::<syn::DeriveInput>(input).expect("syn::parse failed");
25 let type_name = ast.ident.clone();
26
27 match ast.data.clone() {
28 Data::Struct(DataStruct{fields: Fields::Named(named), ..}) => {
29 let fields = named.named.into_iter().collect::<Vec<_>>();
30 into_generic_struct(&type_name, &fields)
31 }
32 Data::Struct(DataStruct{fields: Fields::Unnamed(xs), ..}) => {
33 into_generic_tuple_struct(&type_name, xs)
34 }
35 Data::Struct(DataStruct{fields: Fields::Unit, ..}) => {
36 unimplemented!("Unit structs not yet supported")
37 }
38 Data::Enum(xs) => {
39 let variants = xs.variants
40 .into_iter()
41 .collect::<Vec<_>>();
42 into_generic_enum(&type_name, &variants)
43 }
44 Data::Union(_) => {
45 unimplemented!("Union types not yet supported")
46 }
47 }
48}
49
50
51fn into_generic_struct(type_name: &proc_macro2::Ident, fields: &[Field]) -> proc_macro::TokenStream {
56 let field_conversions = fields
57 .iter()
58 .map(|field| {
59 let field_ident = field.ident
60 .clone()
61 .expect("missing ident");
62 quote! {
63 let key = stringify!(#field_ident).to_owned();
64 let value = IntoGeneric::into_generic(&self.#field_ident);
65 map.insert(key, value);
66 }
67 })
68 .collect::<Vec<_>>();
69 let gen = quote! {
70 impl IntoGeneric for #type_name {
71 fn into_generic(&self) -> Value {
72 use generic_core::into::*;
73 use generic_core::value::*;
74
75 let mut map: HashMap<String, Value> = std::collections::HashMap::new();
76 #(#field_conversions)*
77 Value::Struct(Struct {
78 type_name: String::from(stringify!(#type_name)),
79 data: map,
80 })
81 }
82 }
83 };
84 gen.into()
85}
86
87
88fn into_generic_tuple_struct(type_name: &proc_macro2::Ident, fields: FieldsUnnamed) -> proc_macro::TokenStream {
93 let field_conversions = fields.unnamed
94 .iter()
95 .enumerate()
96 .map(|(ix, _)| {
97 let ix = syn::Index::from(ix);
98 quote!{
99 let value = IntoGeneric::into_generic(&self.#ix);
100 vec.push(value);
101 }
102 })
103 .collect::<Vec<_>>();
104 let gen = quote! {
105 impl IntoGeneric for #type_name {
106 fn into_generic(&self) -> Value {
107 use generic_core::into::*;
108 use generic_core::value::*;
109
110 let mut vec = Vec::<Value>::new();
111
112 #(#field_conversions)*
113 Value::TupleStruct(TupleStruct {
114 type_name: String::from(stringify!(#type_name)),
115 data: vec,
116 })
117 }
118 }
119 };
120 gen.into()
121}
122
123
124fn into_generic_enum(type_name: &proc_macro2::Ident, variants: &[Variant]) -> proc_macro::TokenStream {
129 let arms = variants
130 .iter()
131 .map(|var| {
132 let variant_name = &var.ident;
133 match var.fields.clone() {
134 Fields::Named(xs) => {
135 let (ident_binders, to_generics) = xs.named
136 .iter()
137 .map(|x| {
138 let ident = x.ident.clone().expect("todo - tuple structs");
139 let binder = quote!{
140 ref #ident,
141 };
142 let to_generic = quote!{
143 let key = stringify!(#ident).to_owned();
144 let value = IntoGeneric::into_generic(#ident);
145 map.insert(key, value);
146 };
147 (binder, to_generic)
148 })
149 .unzip::<_, _, Vec<_>, Vec<_>>();
150 quote! {
151 #type_name::#variant_name{#(#ident_binders)*} => {
152 let mut map = std::collections::HashMap::<String, Value>::new();
153
154 #(#to_generics)*
155
156 Value::Variant(Variant::StructVariant {
157 type_name: stringify!(#type_name).to_owned(),
158 variant_name: stringify!(#variant_name).to_owned(),
159 data: map,
160 })
161 }
162 }
163 },
164 Fields::Unnamed(xs) => {
165 let (ident_binders, to_generics) = xs.unnamed
166 .iter()
167 .map(|_| {
168 let ident = format!("id_{}", rand::random::<u16>());
169 let ident = proc_macro2::Ident::new(&ident, proc_macro2::Span::call_site());
170 let binder = quote!{
171 ref #ident,
172 };
173 let to_generic = quote!{
174 let value = IntoGeneric::into_generic(#ident);
175 vec.push(value);
176 };
177 (binder, to_generic)
178 })
179 .unzip::<_, _, Vec<_>, Vec<_>>();
180 quote! {
181 #type_name::#variant_name(#(#ident_binders)*) => {
182 let mut vec = Vec::<Value>::new();
183
184 #(#to_generics)*
185
186 Value::Variant(Variant::TupleVariant {
187 type_name: stringify!(#type_name).to_owned(),
188 variant_name: stringify!(#variant_name).to_owned(),
189 data: vec,
190 })
191 }
192 }
193 },
194 Fields::Unit => {
195 quote! {
196 #type_name::#variant_name => {
197 Value::Variant(Variant::UnitVariant{
198 type_name: stringify!(#type_name).to_owned(),
199 variant_name: stringify!(#variant_name).to_owned(),
200 })
201 }
202 }
203 },
204 }
205 });
206 let gen = quote! {
207 impl IntoGeneric for #type_name {
208 fn into_generic(&self) -> Value {
209 use generic_core::into::*;
210 use generic_core::value::*;
211
212 match self {
213 #(#arms)*
214 }
215 }
216 }
217 };
218 gen.into()
219}
220