bindgen/codegen/
impl_debug.rs
1use crate::ir::comp::{BitfieldUnit, CompKind, Field, FieldData, FieldMethods};
2use crate::ir::context::BindgenContext;
3use crate::ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName};
4use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
5use std::fmt::Write as _;
6
7pub(crate) fn gen_debug_impl(
8 ctx: &BindgenContext,
9 fields: &[Field],
10 item: &Item,
11 kind: CompKind,
12) -> proc_macro2::TokenStream {
13 let struct_name = item.canonical_name(ctx);
14 let mut format_string = format!("{struct_name} {{{{ ");
15 let mut tokens = vec![];
16
17 if item.is_opaque(ctx, &()) {
18 format_string.push_str("opaque");
19 } else {
20 match kind {
21 CompKind::Union => {
22 format_string.push_str("union");
23 }
24 CompKind::Struct => {
25 let processed_fields = fields.iter().filter_map(|f| match f {
26 Field::DataMember(ref fd) => fd.impl_debug(ctx, ()),
27 Field::Bitfields(ref bu) => bu.impl_debug(ctx, ()),
28 });
29
30 for (i, (fstring, toks)) in processed_fields.enumerate() {
31 if i > 0 {
32 format_string.push_str(", ");
33 }
34 tokens.extend(toks);
35 format_string.push_str(&fstring);
36 }
37 }
38 }
39 }
40
41 format_string.push_str(" }}");
42 tokens.insert(0, quote! { #format_string });
43
44 let prefix = ctx.trait_prefix();
45
46 quote! {
47 fn fmt(&self, f: &mut ::#prefix::fmt::Formatter<'_>) -> ::#prefix ::fmt::Result {
48 write!(f, #( #tokens ),*)
49 }
50 }
51}
52
53pub(crate) trait ImplDebug<'a> {
56 type Extra;
58
59 fn impl_debug(
62 &self,
63 ctx: &BindgenContext,
64 extra: Self::Extra,
65 ) -> Option<(String, Vec<proc_macro2::TokenStream>)>;
66}
67
68impl ImplDebug<'_> for FieldData {
69 type Extra = ();
70
71 fn impl_debug(
72 &self,
73 ctx: &BindgenContext,
74 _: Self::Extra,
75 ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
76 if let Some(name) = self.name() {
77 ctx.resolve_item(self.ty()).impl_debug(ctx, name)
78 } else {
79 None
80 }
81 }
82}
83
84impl ImplDebug<'_> for BitfieldUnit {
85 type Extra = ();
86
87 fn impl_debug(
88 &self,
89 ctx: &BindgenContext,
90 _: Self::Extra,
91 ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
92 let mut format_string = String::new();
93 let mut tokens = vec![];
94 for (i, bitfield) in self.bitfields().iter().enumerate() {
95 if i > 0 {
96 format_string.push_str(", ");
97 }
98
99 if let Some(bitfield_name) = bitfield.name() {
100 let _ = write!(format_string, "{bitfield_name} : {{:?}}");
101 let getter_name = bitfield.getter_name();
102 let name_ident = ctx.rust_ident_raw(getter_name);
103 tokens.push(quote! {
104 self.#name_ident ()
105 });
106 }
107 }
108
109 Some((format_string, tokens))
110 }
111}
112
113impl<'a> ImplDebug<'a> for Item {
114 type Extra = &'a str;
115
116 fn impl_debug(
117 &self,
118 ctx: &BindgenContext,
119 name: &str,
120 ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
121 let name_ident = ctx.rust_ident(name);
122
123 if !ctx.allowlisted_items().contains(&self.id()) {
126 return None;
127 }
128
129 let ty = self.as_type()?;
130
131 fn debug_print(
132 name: &str,
133 name_ident: proc_macro2::TokenStream,
134 ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
135 Some((
136 format!("{name}: {{:?}}"),
137 vec![quote! {
138 self.#name_ident
139 }],
140 ))
141 }
142
143 match *ty.kind() {
144 TypeKind::Void |
146 TypeKind::NullPtr |
147 TypeKind::Int(..) |
148 TypeKind::Float(..) |
149 TypeKind::Complex(..) |
150 TypeKind::Function(..) |
151 TypeKind::Enum(..) |
152 TypeKind::Reference(..) |
153 TypeKind::UnresolvedTypeRef(..) |
154 TypeKind::ObjCInterface(..) |
155 TypeKind::ObjCId |
156 TypeKind::Comp(..) |
157 TypeKind::ObjCSel => debug_print(name, quote! { #name_ident }),
158
159 TypeKind::TemplateInstantiation(ref inst) => {
160 if inst.is_opaque(ctx, self) {
161 Some((format!("{name}: opaque"), vec![]))
162 } else {
163 debug_print(name, quote! { #name_ident })
164 }
165 }
166
167 TypeKind::TypeParam => {
169 Some((format!("{name}: Non-debuggable generic"), vec![]))
170 }
171
172 TypeKind::Array(_, len) => {
173 if self.has_type_param_in_array(ctx) {
175 Some((format!("{name}: Array with length {len}"), vec![]))
176 } else if len < RUST_DERIVE_IN_ARRAY_LIMIT ||
177 ctx.options().rust_features().larger_arrays
178 {
179 debug_print(name, quote! { #name_ident })
181 } else if ctx.options().use_core {
182 Some((format!("{name}: [...]"), vec![]))
185 } else {
186 Some((
188 format!("{name}: [{{}}]"),
189 vec![quote! {{
190 use std::fmt::Write as _;
191 let mut output = String::new();
192 let mut iter = self.#name_ident.iter();
193 if let Some(value) = iter.next() {
194 let _ = write!(output, "{value:?}");
195 for value in iter {
196 let _ = write!(output, ", {value:?}");
197 }
198 }
199 output
200 }}],
201 ))
202 }
203 }
204 TypeKind::Vector(_, len) => {
205 if ctx.options().use_core {
206 Some((format!("{name}(...)"), vec![]))
209 } else {
210 let self_ids = 0..len;
211 Some((
212 format!("{name}({{}})"),
213 vec![quote! {
214 #(format!("{:?}", self.#self_ids)),*
215 }],
216 ))
217 }
218 }
219
220 TypeKind::ResolvedTypeRef(t) |
221 TypeKind::TemplateAlias(t, _) |
222 TypeKind::Alias(t) |
223 TypeKind::BlockPointer(t) => {
224 ctx.resolve_item(t).impl_debug(ctx, name)
226 }
227
228 TypeKind::Pointer(inner) => {
229 let inner_type = ctx.resolve_type(inner).canonical_type(ctx);
230 match *inner_type.kind() {
231 TypeKind::Function(ref sig)
232 if !sig.function_pointers_can_derive() =>
233 {
234 Some((format!("{name}: FunctionPointer"), vec![]))
235 }
236 _ => debug_print(name, quote! { #name_ident }),
237 }
238 }
239
240 TypeKind::Opaque => None,
241 }
242 }
243}