educe/trait_handlers/debug/
debug_union.rs1use 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}