educe/trait_handlers/debug/
debug_union.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{Data, DeriveInput, Generics, Meta};
4
5use super::{
6    super::TraitHandler,
7    models::{FieldAttributeBuilder, FieldAttributeName, TypeAttributeBuilder, TypeAttributeName},
8};
9use crate::Trait;
10
11pub struct DebugUnionHandler;
12
13impl TraitHandler for DebugUnionHandler {
14    fn trait_meta_handler(
15        ast: &DeriveInput,
16        tokens: &mut TokenStream,
17        traits: &[Trait],
18        meta: &Meta,
19    ) {
20        let type_attribute = TypeAttributeBuilder {
21            enable_flag:        true,
22            name:               TypeAttributeName::Default,
23            enable_name:        true,
24            named_field:        false,
25            enable_named_field: false,
26            enable_bound:       true,
27        }
28        .from_debug_meta(meta);
29
30        let name = type_attribute.name.into_string_by_ident(&ast.ident);
31
32        let bound = type_attribute
33            .bound
34            .into_punctuated_where_predicates_by_generic_parameters(&ast.generics.params);
35
36        let mut builder_tokens = TokenStream::new();
37
38        if let Data::Union(data) = &ast.data {
39            for field in data.fields.named.iter() {
40                let _ = FieldAttributeBuilder {
41                    name:          FieldAttributeName::Default,
42                    enable_name:   false,
43                    enable_ignore: false,
44                    enable_impl:   false,
45                }
46                .from_attributes(&field.attrs, traits);
47            }
48
49            if name.is_empty() {
50                builder_tokens.extend(quote!(
51                    let size = core::mem::size_of::<Self>();
52                    let data = unsafe {{ core::slice::from_raw_parts(self as *const Self as *const u8, size) }};
53
54                    core::fmt::Debug::fmt(data, formatter)
55                ));
56            } else {
57                builder_tokens.extend(quote!(
58                    let mut builder = formatter.debug_tuple(#name);
59
60                    let size = core::mem::size_of::<Self>();
61
62                    let data = unsafe {{ core::slice::from_raw_parts(self as *const Self as *const u8, size) }};
63
64                    builder.field(&data);
65
66                    builder.finish()
67                ));
68            }
69        }
70
71        let ident = &ast.ident;
72
73        let mut generics_cloned: Generics = ast.generics.clone();
74
75        let where_clause = generics_cloned.make_where_clause();
76
77        where_clause.predicates.extend(bound.iter().cloned());
78
79        let (impl_generics, ty_generics, where_clause) = generics_cloned.split_for_impl();
80
81        let debug_impl = quote! {
82            impl #impl_generics core::fmt::Debug for #ident #ty_generics #where_clause {
83                #[inline]
84                fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
85                    #builder_tokens
86                }
87            }
88        };
89
90        tokens.extend(debug_impl);
91    }
92}