error_generator/impl_from/
enums.rs1use quote::quote;
2use syn::{FieldsNamed, FieldsUnnamed, ItemEnum, Variant};
3use syn::__private::TokenStream2;
4use syn::Fields::*;
5
6use crate::enum_error::VariantWithParams;
7use crate::impl_from::FromImplementationError;
8use crate::impl_from::FromImplementationError::{EnumNotExactlyOneField, ParameterOnEnumAndVariant};
9use crate::parameters::{IMPL_FROM, Parameters};
10
11pub struct EnumFromImplementer<'a> {
12 item_enum: &'a ItemEnum,
13 enum_parameters: &'a Parameters,
14 variants_with_parameters: &'a Vec<VariantWithParams<'a>>,
15}
16
17impl<'a> EnumFromImplementer<'a> {
18 pub fn new(item_enum: &'a ItemEnum, enum_parameters: &'a Parameters, variants_with_parameters: &'a Vec<VariantWithParams<'a>>) -> Self {
19 EnumFromImplementer { item_enum, enum_parameters, variants_with_parameters }
20 }
21
22 pub fn implement(self) -> Result<TokenStream2, FromImplementationError> {
32 let global_implement = self.enum_parameters.bool_for_name(IMPL_FROM);
33 let impl_from_variants = self.get_impl_from_variants();
34
35 self.validate_impl_from_settings(global_implement, &impl_from_variants)?;
36
37 let implementations = match global_implement {
38 true => self.implement_for_variants(self.item_enum.variants.iter()),
39 false => self.implement_for_variants(impl_from_variants)
40 };
41
42 Ok(quote! {#(#implementations)*})
43 }
44
45 fn get_impl_from_variants(&self) -> Vec<&Variant> {
47 self.variants_with_parameters
48 .iter()
49 .filter_map(|(v, p_opt)| match p_opt {
50 Some(p) => Some((v, p)),
51 _ => None
52 })
53 .filter_map(|(v, p)| match p.bool_for_name(IMPL_FROM) {
54 true => Some(*v),
55 false => None
56 })
57 .collect()
58 }
59
60 fn validate_impl_from_settings(&self, global_impl_from: bool, impl_from_variants: &Vec<&Variant>) -> Result<(), FromImplementationError> {
71 if global_impl_from && impl_from_variants.len() > 0 {
72 return Err(ParameterOnEnumAndVariant(self.item_enum.ident.clone()));
73 }
74
75 let variant_idents_with_not_one_field = match global_impl_from {
76 true => self.item_enum.variants.iter()
77 .filter(|v| self.variant_num_fields(v) != 1)
78 .map(|v| v.ident.clone())
79 .collect::<Vec<_>>(),
80 false => impl_from_variants.iter()
81 .filter(|v| self.variant_num_fields(v) != 1)
82 .map(|v| v.ident.clone())
83 .collect::<Vec<_>>()
84 };
85
86 match variant_idents_with_not_one_field.len() {
87 0 => Ok(()),
88 _ => Err(EnumNotExactlyOneField(self.item_enum.ident.clone(), variant_idents_with_not_one_field))
89 }
90 }
91
92 fn variant_num_fields(&self, variant: &Variant) -> usize {
93 match &variant.fields {
94 Named(f) => f.named.len(),
95 Unnamed(f) => f.unnamed.len(),
96 Unit => 0
97 }
98 }
99
100 fn implement_for_variants<'b, I>(&self, variants: I) -> Vec<TokenStream2>
101 where I: IntoIterator<Item=&'b Variant> {
102 variants.into_iter()
103 .map(|v| self.implement_for_variant(v))
104 .collect()
105 }
106
107 fn implement_for_variant(&self, variant: &Variant) -> TokenStream2 {
108 match &variant.fields {
109 Named(ref fields) => self.implement_for_named(variant, fields),
110 Unnamed(ref fields) => self.implement_for_unnamed(variant, fields),
111 Unit => unreachable!()
112 }
113 }
114
115 fn implement_for_named(&self, variant: &Variant, fields: &FieldsNamed) -> TokenStream2 {
116 let enum_ident = &self.item_enum.ident;
117 let generics = &self.item_enum.generics;
118 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
119 let variant_ident = &variant.ident;
120 let field = fields.named.first().unwrap();
121 let ty = &field.ty;
122 let field_ident = field.ident.as_ref().unwrap();
123
124 quote! {
125 impl #impl_generics std::convert::From<#ty> for #enum_ident #type_generics #where_clause {
126 fn from(val: #ty) -> Self {
127 #enum_ident::#variant_ident{ #field_ident : val }
128 }
129 }
130 }
131 }
132
133 fn implement_for_unnamed(&self, variant: &Variant, fields: &FieldsUnnamed) -> TokenStream2 {
134 let enum_ident = &self.item_enum.ident;
135 let generics = &self.item_enum.generics;
136 let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
137 let variant_ident = &variant.ident;
138 let field = fields.unnamed.first().unwrap();
139 let ty = &field.ty;
140
141 quote! {
142 impl #impl_generics std::convert::From<#ty> for #enum_ident #type_generics #where_clause {
143 fn from(val: #ty) -> Self {
144 #enum_ident::#variant_ident(val)
145 }
146 }
147 }
148 }
149}