diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
| commit | 8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch) | |
| tree | 22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/educe/src/trait_handlers/debug/debug_enum.rs | |
| parent | 4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff) | |
chore: add vendor directory
Diffstat (limited to 'vendor/educe/src/trait_handlers/debug/debug_enum.rs')
| -rw-r--r-- | vendor/educe/src/trait_handlers/debug/debug_enum.rs | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/vendor/educe/src/trait_handlers/debug/debug_enum.rs b/vendor/educe/src/trait_handlers/debug/debug_enum.rs new file mode 100644 index 00000000..1e423818 --- /dev/null +++ b/vendor/educe/src/trait_handlers/debug/debug_enum.rs @@ -0,0 +1,371 @@ +use quote::{format_ident, quote, ToTokens}; +use syn::{Data, DeriveInput, Fields, Meta, Type}; + +use super::models::{FieldAttributeBuilder, FieldName, TypeAttributeBuilder, TypeName}; +use crate::{common::path::path_to_string, supported_traits::Trait, trait_handlers::TraitHandler}; + +pub(crate) struct DebugEnumHandler; + +impl TraitHandler for DebugEnumHandler { + fn trait_meta_handler( + ast: &DeriveInput, + token_stream: &mut proc_macro2::TokenStream, + traits: &[Trait], + meta: &Meta, + ) -> syn::Result<()> { + let type_attribute = TypeAttributeBuilder { + enable_flag: true, + enable_unsafe: false, + enable_name: true, + enable_named_field: false, + enable_bound: true, + name: TypeName::Disable, + named_field: false, + } + .build_from_debug_meta(meta)?; + + let name = type_attribute.name.to_ident_by_ident(&ast.ident); + + let mut debug_types: Vec<&Type> = Vec::new(); + + let mut builder_token_stream = proc_macro2::TokenStream::new(); + + let mut arms_token_stream = proc_macro2::TokenStream::new(); + + if let Data::Enum(data) = &ast.data { + for variant in data.variants.iter() { + let type_attribute = TypeAttributeBuilder { + enable_flag: false, + enable_unsafe: false, + enable_name: true, + enable_named_field: true, + enable_bound: false, + name: TypeName::Default, + named_field: matches!(&variant.fields, Fields::Named(_)), + } + .build_from_attributes(&variant.attrs, traits)?; + + let variant_ident = &variant.ident; + + let variant_name = type_attribute.name.to_ident_by_ident(variant_ident); + + let named_field = type_attribute.named_field; + + let name_string = if let Some(name) = name { + if let Some(variant_name) = variant_name { + Some(path_to_string(&syn::parse2(quote!(#name::#variant_name)).unwrap())) + } else { + Some(name.into_token_stream().to_string()) + } + } else { + variant_name.map(|variant_name| variant_name.into_token_stream().to_string()) + }; + + match &variant.fields { + Fields::Unit => { + if name_string.is_none() { + return Err(super::panic::unit_variant_need_name(variant)); + } + + arms_token_stream + .extend(quote!( Self::#variant_ident => f.write_str(#name_string), )); + }, + Fields::Named(fields) => { + let mut has_fields = false; + + let mut pattern_token_stream = proc_macro2::TokenStream::new(); + let mut block_token_stream = proc_macro2::TokenStream::new(); + + if named_field { + block_token_stream + .extend(create_named_field_builder(name_string.as_deref())); + + for field in fields.named.iter() { + let field_attribute = FieldAttributeBuilder { + enable_name: true, + enable_ignore: true, + enable_method: true, + name: FieldName::Default, + } + .build_from_attributes(&field.attrs, traits)?; + + let field_name_real = field.ident.as_ref().unwrap(); + let field_name_var = format_ident!("_{}", field_name_real); + + if field_attribute.ignore { + pattern_token_stream.extend(quote!(#field_name_real: _,)); + + continue; + } + + let key = match field_attribute.name { + FieldName::Custom(name) => name, + FieldName::Default => field_name_real.clone(), + }; + + pattern_token_stream + .extend(quote!(#field_name_real: #field_name_var,)); + + let ty = &field.ty; + + if let Some(method) = field_attribute.method { + block_token_stream.extend(super::common::create_format_arg( + ast, + ty, + &method, + quote!(#field_name_var), + )); + + block_token_stream.extend(if name_string.is_some() { + quote! (builder.field(stringify!(#key), &arg);) + } else { + quote! (builder.entry(&Educe__RawString(stringify!(#key)), &arg);) + }); + } else { + debug_types.push(ty); + + block_token_stream.extend(if name_string.is_some() { + quote! (builder.field(stringify!(#key), #field_name_var);) + } else { + quote! (builder.entry(&Educe__RawString(stringify!(#key)), #field_name_var);) + }); + } + + has_fields = true; + } + } else { + block_token_stream + .extend(quote!(let mut builder = f.debug_tuple(#name_string);)); + + for field in fields.named.iter() { + let field_attribute = FieldAttributeBuilder { + enable_name: false, + enable_ignore: true, + enable_method: true, + name: FieldName::Default, + } + .build_from_attributes(&field.attrs, traits)?; + + let field_name_real = field.ident.as_ref().unwrap(); + let field_name_var = format_ident!("_{}", field_name_real); + + if field_attribute.ignore { + pattern_token_stream.extend(quote!(#field_name_real: _,)); + + continue; + } + + pattern_token_stream + .extend(quote!(#field_name_real: #field_name_var,)); + + let ty = &field.ty; + + if let Some(method) = field_attribute.method { + block_token_stream.extend(super::common::create_format_arg( + ast, + ty, + &method, + quote!(#field_name_var), + )); + + block_token_stream.extend(quote! (builder.field(&arg);)); + } else { + debug_types.push(ty); + + block_token_stream + .extend(quote! (builder.field(#field_name_var);)); + } + + has_fields = true; + } + } + + if !has_fields && name_string.is_none() { + return Err(super::panic::unit_struct_need_name(variant_ident)); + } + + arms_token_stream.extend(quote! { + Self::#variant_ident { #pattern_token_stream } => { + #block_token_stream + + builder.finish() + }, + }); + }, + Fields::Unnamed(fields) => { + let mut has_fields = false; + + let mut pattern_token_stream = proc_macro2::TokenStream::new(); + let mut block_token_stream = proc_macro2::TokenStream::new(); + + if named_field { + block_token_stream + .extend(create_named_field_builder(name_string.as_deref())); + + for (index, field) in fields.unnamed.iter().enumerate() { + let field_attribute = FieldAttributeBuilder { + enable_name: true, + enable_ignore: true, + enable_method: true, + name: FieldName::Default, + } + .build_from_attributes(&field.attrs, traits)?; + + if field_attribute.ignore { + pattern_token_stream.extend(quote!(_,)); + + continue; + } + + let field_name_var = format_ident!("_{}", index); + + let key = match field_attribute.name { + FieldName::Custom(name) => name, + FieldName::Default => field_name_var.clone(), + }; + + pattern_token_stream.extend(quote!(#field_name_var,)); + + let ty = &field.ty; + + if let Some(method) = field_attribute.method { + block_token_stream.extend(super::common::create_format_arg( + ast, + ty, + &method, + quote!(#field_name_var), + )); + + block_token_stream.extend(if name_string.is_some() { + quote! (builder.field(stringify!(#key), &arg);) + } else { + quote! (builder.entry(&Educe__RawString(stringify!(#key)), &arg);) + }); + } else { + debug_types.push(ty); + + block_token_stream.extend(if name_string.is_some() { + quote! (builder.field(stringify!(#key), #field_name_var);) + } else { + quote! (builder.entry(&Educe__RawString(stringify!(#key)), #field_name_var);) + }); + } + + has_fields = true; + } + } else { + block_token_stream + .extend(quote!(let mut builder = f.debug_tuple(#name_string);)); + + for (index, field) in fields.unnamed.iter().enumerate() { + let field_attribute = FieldAttributeBuilder { + enable_name: false, + enable_ignore: true, + enable_method: true, + name: FieldName::Default, + } + .build_from_attributes(&field.attrs, traits)?; + + if field_attribute.ignore { + pattern_token_stream.extend(quote!(_,)); + + continue; + } + + let field_name_var = format_ident!("_{}", index); + + pattern_token_stream.extend(quote!(#field_name_var,)); + + let ty = &field.ty; + + if let Some(method) = field_attribute.method { + block_token_stream.extend(super::common::create_format_arg( + ast, + ty, + &method, + quote!(#field_name_var), + )); + + block_token_stream.extend(quote! (builder.field(&arg);)); + } else { + debug_types.push(ty); + + block_token_stream + .extend(quote! (builder.field(#field_name_var);)); + } + + has_fields = true; + } + } + + if !has_fields && name_string.is_none() { + return Err(super::panic::unit_struct_need_name(variant_ident)); + } + + arms_token_stream.extend(quote! { + Self::#variant_ident ( #pattern_token_stream ) => { + #block_token_stream + + builder.finish() + }, + }); + }, + } + } + } + + let ident = &ast.ident; + + if arms_token_stream.is_empty() { + if let Some(ident) = name { + builder_token_stream.extend(quote! { + f.write_str(stringify!(#ident)) + }); + } else { + return Err(super::panic::unit_enum_need_name(ident)); + } + } else { + builder_token_stream.extend(quote! { + match self { + #arms_token_stream + } + }); + } + + let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types( + &ast.generics.params, + &syn::parse2(quote!(::core::fmt::Debug)).unwrap(), + &debug_types, + &[], + ); + + let mut generics = ast.generics.clone(); + let where_clause = generics.make_where_clause(); + + for where_predicate in bound { + where_clause.predicates.push(where_predicate); + } + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + token_stream.extend(quote! { + impl #impl_generics ::core::fmt::Debug for #ident #ty_generics #where_clause { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + #builder_token_stream + } + } + }); + + Ok(()) + } +} + +#[inline] +fn create_named_field_builder(name_string: Option<&str>) -> proc_macro2::TokenStream { + if let Some(name_string) = name_string { + quote!(let mut builder = f.debug_struct(#name_string);) + } else { + super::common::create_debug_map_builder() + } +} |
