|
| 1 | +use crate::models::{DisplayCase, Meta}; |
| 2 | +use proc_macro2::{Ident, TokenStream}; |
| 3 | +use quote::quote; |
| 4 | + |
| 5 | +pub fn gen_kind_enum(meta: &Meta) -> TokenStream { |
| 6 | + let kind_enum_definition = gen_definition(meta); |
| 7 | + let impl_from_traits = gen_impl_from_traits(meta); |
| 8 | + let impl_display_trait = gen_impl_display_trait(meta); |
| 9 | + |
| 10 | + quote!( |
| 11 | + #kind_enum_definition |
| 12 | + #impl_from_traits |
| 13 | + #impl_display_trait |
| 14 | + ) |
| 15 | +} |
| 16 | + |
| 17 | +fn gen_definition(meta: &Meta) -> TokenStream { |
| 18 | + let vis = &meta.vis; |
| 19 | + let kind_name = meta.kind_name(); |
| 20 | + let variant_names: Vec<&Ident> = meta.variants.iter().map(|v| &v.ident).collect(); |
| 21 | + let traits = meta.derive_traits(); |
| 22 | + |
| 23 | + quote!( |
| 24 | + #[derive(#(#traits),*)] // #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 25 | + #vis enum #kind_name { // pub enum DrinkKind { |
| 26 | + #(#variant_names),* // Mate, Coffee, Tea |
| 27 | + } // } |
| 28 | + |
| 29 | + impl #kind_name { // impl DrinkKind { |
| 30 | + pub fn all() -> impl Iterator<Item = #kind_name> { // pub fn all() -> impl Iterator<Item = DrinkKind> { |
| 31 | + [ // [ |
| 32 | + #(#kind_name::#variant_names),* // DrinkKind::Mate, DrinkKind::Coffee, DrinkKind::Tea |
| 33 | + ].into_iter() // ] |
| 34 | + } // } |
| 35 | + } // } |
| 36 | + ) |
| 37 | +} |
| 38 | + |
| 39 | +fn gen_impl_from_traits(meta: &Meta) -> TokenStream { |
| 40 | + let kind_name = meta.kind_name(); |
| 41 | + let generics = &meta.generics; |
| 42 | + let main_enum_with_generics = meta.main_enum_with_generics(); |
| 43 | + |
| 44 | + quote!( |
| 45 | + impl #generics From<#main_enum_with_generics> for #kind_name { // impl<T> From<Drink<T>> for DrinkKind { |
| 46 | + fn from(value: #main_enum_with_generics) -> #kind_name { // fn from(value: Drink<T>) -> DrinkKind { |
| 47 | + value.kind() // value.kind() |
| 48 | + } // } |
| 49 | + } // } |
| 50 | + |
| 51 | + impl #generics From<&#main_enum_with_generics> for #kind_name { // impl<T> From<Drink<T>> for DrinkKind { |
| 52 | + fn from(value: &#main_enum_with_generics) -> #kind_name { // fn from(value: &Drink<T>) -> DrinkKind { |
| 53 | + value.kind() // value.kind() |
| 54 | + } // } |
| 55 | + } // } |
| 56 | + ) |
| 57 | +} |
| 58 | + |
| 59 | +fn gen_impl_display_trait(meta: &Meta) -> TokenStream { |
| 60 | + let kind_name = meta.kind_name(); |
| 61 | + let maybe_case = meta.kinded_attrs.display; |
| 62 | + |
| 63 | + let match_branches = meta.variants.iter().map(|variant| { |
| 64 | + let original_variant_name_str = variant.ident.to_string(); |
| 65 | + let cased_variant_name = apply_display_case(original_variant_name_str, maybe_case); |
| 66 | + let variant_name = &variant.ident; |
| 67 | + quote!( |
| 68 | + #kind_name::#variant_name => write!(f, #cased_variant_name) |
| 69 | + ) |
| 70 | + }); |
| 71 | + |
| 72 | + quote!( |
| 73 | + impl std::fmt::Display for #kind_name { // impl std::fmt::Display for DrinkKind { |
| 74 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 75 | + match self { // match self { |
| 76 | + #(#match_branches),* // DrinkKind::Mate => write!(f, "mate"), |
| 77 | + } // } |
| 78 | + } // } |
| 79 | + } // |
| 80 | + ) |
| 81 | +} |
| 82 | + |
| 83 | +fn apply_display_case(original: String, maybe_display_case: Option<DisplayCase>) -> String { |
| 84 | + use convert_case::{Case, Casing}; |
| 85 | + |
| 86 | + if let Some(display_case) = maybe_display_case { |
| 87 | + let case: Case = display_case.into(); |
| 88 | + original.to_case(case) |
| 89 | + } else { |
| 90 | + original |
| 91 | + } |
| 92 | +} |
0 commit comments