bindgen/codegen/
helpers.rs1use proc_macro2::{Ident, Span};
4
5use crate::ir::context::BindgenContext;
6use crate::ir::layout::Layout;
7
8pub(crate) mod attributes {
9 use proc_macro2::{Ident, Span, TokenStream};
10 use std::{borrow::Cow, str::FromStr};
11
12 pub(crate) fn repr(which: &str) -> TokenStream {
13 let which = Ident::new(which, Span::call_site());
14 quote! {
15 #[repr( #which )]
16 }
17 }
18
19 pub(crate) fn repr_list(which_ones: &[&str]) -> TokenStream {
20 let which_ones = which_ones
21 .iter()
22 .map(|one| TokenStream::from_str(one).expect("repr to be valid"));
23 quote! {
24 #[repr( #( #which_ones ),* )]
25 }
26 }
27
28 pub(crate) fn derives(which_ones: &[&str]) -> TokenStream {
29 let which_ones = which_ones
30 .iter()
31 .map(|one| TokenStream::from_str(one).expect("derive to be valid"));
32 quote! {
33 #[derive( #( #which_ones ),* )]
34 }
35 }
36
37 pub(crate) fn inline() -> TokenStream {
38 quote! {
39 #[inline]
40 }
41 }
42
43 pub(crate) fn must_use() -> TokenStream {
44 quote! {
45 #[must_use]
46 }
47 }
48
49 pub(crate) fn non_exhaustive() -> TokenStream {
50 quote! {
51 #[non_exhaustive]
52 }
53 }
54
55 pub(crate) fn doc(comment: &str) -> TokenStream {
56 if comment.is_empty() {
57 quote!()
58 } else {
59 quote!(#[doc = #comment])
60 }
61 }
62
63 pub(crate) fn link_name<const MANGLE: bool>(name: &str) -> TokenStream {
64 let name: Cow<'_, str> = if MANGLE {
67 name.into()
68 } else {
69 format!("\u{1}{name}").into()
70 };
71
72 quote! {
73 #[link_name = #name]
74 }
75 }
76}
77
78pub(crate) fn blob(
84 ctx: &BindgenContext,
85 layout: Layout,
86 ffi_safe: bool,
87) -> syn::Type {
88 let opaque = layout.opaque();
89
90 let ty = opaque.known_rust_type_for_array().unwrap_or_else(|| {
95 warn!("Found unknown alignment on code generation!");
96 syn::parse_quote! { u8 }
97 });
98
99 let data_len = opaque.array_size().unwrap_or(layout.size);
100
101 if data_len == 1 {
102 ty
103 } else if ffi_safe && ctx.options().rust_features().min_const_generics {
104 ctx.generated_opaque_array();
105 if ctx.options().enable_cxx_namespaces {
106 syn::parse_quote! { root::__BindgenOpaqueArray<#ty, #data_len> }
107 } else {
108 syn::parse_quote! { __BindgenOpaqueArray<#ty, #data_len> }
109 }
110 } else {
111 syn::parse_quote! { [ #ty ; #data_len ] }
114 }
115}
116
117pub(crate) fn integer_type(layout: Layout) -> Option<syn::Type> {
119 Layout::known_type_for_size(layout.size)
120}
121
122pub(crate) const BITFIELD_UNIT: &str = "__BindgenBitfieldUnit";
123
124pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type {
126 let size = layout.size;
127 let bitfield_unit_name = Ident::new(BITFIELD_UNIT, Span::call_site());
128 let ty = syn::parse_quote! { #bitfield_unit_name<[u8; #size]> };
129
130 if ctx.options().enable_cxx_namespaces {
131 return syn::parse_quote! { root::#ty };
132 }
133
134 ty
135}
136
137pub(crate) mod ast_ty {
138 use crate::ir::context::BindgenContext;
139 use crate::ir::function::FunctionSig;
140 use crate::ir::layout::Layout;
141 use crate::ir::ty::{FloatKind, IntKind};
142 use crate::RustTarget;
143 use proc_macro2::TokenStream;
144 use std::str::FromStr;
145
146 pub(crate) fn c_void(ctx: &BindgenContext) -> syn::Type {
147 match ctx.options().ctypes_prefix {
149 Some(ref prefix) => {
150 let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
151 syn::parse_quote! { #prefix::c_void }
152 }
153 None => {
154 if ctx.options().use_core {
155 syn::parse_quote! { ::core::ffi::c_void }
156 } else {
157 syn::parse_quote! { ::std::os::raw::c_void }
158 }
159 }
160 }
161 }
162
163 pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> syn::Type {
164 let ident = ctx.rust_ident_raw(name);
165 match ctx.options().ctypes_prefix {
166 Some(ref prefix) => {
167 let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
168 syn::parse_quote! { #prefix::#ident }
169 }
170 None => {
171 if ctx.options().use_core &&
172 ctx.options().rust_features().core_ffi_c
173 {
174 syn::parse_quote! { ::core::ffi::#ident }
175 } else {
176 syn::parse_quote! { ::std::os::raw::#ident }
177 }
178 }
179 }
180 }
181
182 pub(crate) fn int_kind_rust_type(
183 ctx: &BindgenContext,
184 ik: IntKind,
185 layout: Option<Layout>,
186 ) -> syn::Type {
187 match ik {
188 IntKind::Bool => syn::parse_quote! { bool },
189 IntKind::Char { .. } => raw_type(ctx, "c_char"),
190 IntKind::Char16 => syn::parse_quote! { bindgen_cchar16_t },
196 IntKind::SChar => raw_type(ctx, "c_schar"),
197 IntKind::UChar => raw_type(ctx, "c_uchar"),
198 IntKind::Short => raw_type(ctx, "c_short"),
199 IntKind::UShort => raw_type(ctx, "c_ushort"),
200 IntKind::Int => raw_type(ctx, "c_int"),
201 IntKind::UInt => raw_type(ctx, "c_uint"),
202 IntKind::Long => raw_type(ctx, "c_long"),
203 IntKind::ULong => raw_type(ctx, "c_ulong"),
204 IntKind::LongLong => raw_type(ctx, "c_longlong"),
205 IntKind::ULongLong => raw_type(ctx, "c_ulonglong"),
206 IntKind::WChar => {
207 let layout =
208 layout.expect("Couldn't compute wchar_t's layout?");
209 Layout::known_type_for_size(layout.size)
210 .expect("Non-representable wchar_t?")
211 }
212
213 IntKind::I8 => syn::parse_quote! { i8 },
214 IntKind::U8 => syn::parse_quote! { u8 },
215 IntKind::I16 => syn::parse_quote! { i16 },
216 IntKind::U16 => syn::parse_quote! { u16 },
217 IntKind::I32 => syn::parse_quote! { i32 },
218 IntKind::U32 => syn::parse_quote! { u32 },
219 IntKind::I64 => syn::parse_quote! { i64 },
220 IntKind::U64 => syn::parse_quote! { u64 },
221 IntKind::Custom { name, .. } => {
222 syn::parse_str(name).expect("Invalid integer type.")
223 }
224 IntKind::U128 => {
225 if true {
226 syn::parse_quote! { u128 }
227 } else {
228 syn::parse_quote! { [u64; 2] }
231 }
232 }
233 IntKind::I128 => {
234 if true {
235 syn::parse_quote! { i128 }
236 } else {
237 syn::parse_quote! { [u64; 2] }
238 }
239 }
240 }
241 }
242
243 pub(crate) fn float_kind_rust_type(
244 ctx: &BindgenContext,
245 fk: FloatKind,
246 layout: Option<Layout>,
247 ) -> syn::Type {
248 match (fk, ctx.options().convert_floats) {
253 (FloatKind::Float16, _) => {
254 ctx.generated_bindgen_float16();
256 if ctx.options().enable_cxx_namespaces {
257 syn::parse_quote! { root::__BindgenFloat16 }
258 } else {
259 syn::parse_quote! { __BindgenFloat16 }
260 }
261 }
262 (FloatKind::Float, true) => syn::parse_quote! { f32 },
263 (FloatKind::Double, true) => syn::parse_quote! { f64 },
264 (FloatKind::Float, false) => raw_type(ctx, "c_float"),
265 (FloatKind::Double, false) => raw_type(ctx, "c_double"),
266 (FloatKind::LongDouble, _) => {
267 if let Some(layout) = layout {
268 match layout.size {
269 4 => syn::parse_quote! { f32 },
270 8 => syn::parse_quote! { f64 },
271 _ => super::integer_type(layout)
274 .unwrap_or(syn::parse_quote! { f64 }),
275 }
276 } else {
277 debug_assert!(
278 false,
279 "How didn't we know the layout for a primitive type?"
280 );
281 syn::parse_quote! { f64 }
282 }
283 }
284 (FloatKind::Float128, _) => {
285 if true {
286 syn::parse_quote! { u128 }
287 } else {
288 syn::parse_quote! { [u64; 2] }
289 }
290 }
291 }
292 }
293
294 pub(crate) fn int_expr(val: i64) -> TokenStream {
295 let val = proc_macro2::Literal::i64_unsuffixed(val);
297 quote!(#val)
298 }
299
300 pub(crate) fn uint_expr(val: u64) -> TokenStream {
301 let val = proc_macro2::Literal::u64_unsuffixed(val);
303 quote!(#val)
304 }
305
306 pub(crate) fn cstr_expr(mut string: String) -> TokenStream {
307 string.push('\0');
308 let b = proc_macro2::Literal::byte_string(string.as_bytes());
309 quote! {
310 #b
311 }
312 }
313
314 pub(crate) fn float_expr(
315 ctx: &BindgenContext,
316 f: f64,
317 ) -> Result<TokenStream, ()> {
318 if f.is_finite() {
319 let val = proc_macro2::Literal::f64_unsuffixed(f);
320
321 return Ok(quote!(#val));
322 }
323
324 let prefix = ctx.trait_prefix();
325 let rust_target = ctx.options().rust_target;
326
327 if f.is_nan() {
328 #[allow(deprecated)]
330 let tokens = if rust_target >= RustTarget::Stable_1_43 {
331 quote! {
332 f64::NAN
333 }
334 } else {
335 quote! {
336 ::#prefix::f64::NAN
337 }
338 };
339 return Ok(tokens);
340 }
341
342 if f.is_infinite() {
343 let tokens = if f.is_sign_positive() {
344 #[allow(deprecated)]
346 if rust_target >= RustTarget::Stable_1_43 {
347 quote! {
348 f64::INFINITY
349 }
350 } else {
351 quote! {
352 ::#prefix::f64::INFINITY
353 }
354 }
355 } else {
356 #[allow(deprecated)]
358 if rust_target >= RustTarget::Stable_1_43 {
360 quote! {
361 f64::NEG_INFINITY
362 }
363 } else {
364 quote! {
365 ::#prefix::f64::NEG_INFINITY
366 }
367 }
368 };
369 return Ok(tokens);
370 }
371
372 warn!("Unknown non-finite float number: {f:?}");
373 Err(())
374 }
375
376 pub(crate) fn arguments_from_signature(
377 signature: &FunctionSig,
378 ctx: &BindgenContext,
379 ) -> Vec<TokenStream> {
380 let mut unnamed_arguments = 0;
381 signature
382 .argument_types()
383 .iter()
384 .map(|&(ref name, _ty)| {
385 let name = if let Some(ref name) = *name {
386 ctx.rust_ident(name)
387 } else {
388 unnamed_arguments += 1;
389 ctx.rust_ident(format!("arg{unnamed_arguments}"))
390 };
391 quote! { #name }
392 })
393 .collect()
394 }
395}