educe/trait_handlers/debug/
debug_union.rs

1use quote::quote;
2use syn::{Data, DeriveInput, Meta};
3
4use super::{
5    models::{FieldAttributeBuilder, FieldName, TypeAttributeBuilder, TypeName},
6    TraitHandler,
7};
8use crate::supported_traits::Trait;
9
10pub(crate) struct DebugUnionHandler;
11
12impl TraitHandler for DebugUnionHandler {
13    fn trait_meta_handler(
14        ast: &DeriveInput,
15        token_stream: &mut proc_macro2::TokenStream,
16        traits: &[Trait],
17        meta: &Meta,
18    ) -> syn::Result<()> {
19        let type_attribute = TypeAttributeBuilder {
20            enable_flag:        true,
21            enable_unsafe:      true,
22            enable_name:        true,
23            enable_named_field: false,
24            enable_bound:       false,
25            name:               TypeName::Default,
26            named_field:        false,
27        }
28        .build_from_debug_meta(meta)?;
29
30        if !type_attribute.has_unsafe {
31            return Err(super::panic::union_without_unsafe(meta));
32        }
33
34        let name = type_attribute.name.to_ident_by_ident(&ast.ident);
35
36        let mut builder_token_stream = proc_macro2::TokenStream::new();
37
38        if let Data::Union(data) = &ast.data {
39            for field in data.fields.named.iter() {
40                let _ = FieldAttributeBuilder {
41                    enable_name:   false,
42                    enable_ignore: false,
43                    enable_method: false,
44                    name:          FieldName::Default,
45                }
46                .build_from_attributes(&field.attrs, traits)?;
47            }
48
49            if let Some(name) = name {
50                builder_token_stream.extend(quote!(
51                    let mut builder = f.debug_tuple(stringify!(#name));
52
53                    let size = ::core::mem::size_of::<Self>();
54
55                    let data = unsafe { ::core::slice::from_raw_parts(self as *const Self as *const u8, size) };
56
57                    builder.field(&data);
58
59                    builder.finish()
60                ));
61            } else {
62                builder_token_stream.extend(quote!(
63                    let size = ::core::mem::size_of::<Self>();
64                    let data = unsafe { ::core::slice::from_raw_parts(self as *const Self as *const u8, size) };
65
66                    ::core::fmt::Debug::fmt(data, f)
67                ));
68            }
69        }
70
71        let ident = &ast.ident;
72
73        let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
74
75        token_stream.extend(quote! {
76            impl #impl_generics ::core::fmt::Debug for #ident #ty_generics #where_clause {
77                #[inline]
78                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
79                    #builder_token_stream
80                }
81            }
82        });
83
84        Ok(())
85    }
86}