bindgen/codegen/
helpers.rs
1use 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: String) -> 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::SChar => raw_type(ctx, "c_schar"),
191 IntKind::UChar => raw_type(ctx, "c_uchar"),
192 IntKind::Short => raw_type(ctx, "c_short"),
193 IntKind::UShort => raw_type(ctx, "c_ushort"),
194 IntKind::Int => raw_type(ctx, "c_int"),
195 IntKind::UInt => raw_type(ctx, "c_uint"),
196 IntKind::Long => raw_type(ctx, "c_long"),
197 IntKind::ULong => raw_type(ctx, "c_ulong"),
198 IntKind::LongLong => raw_type(ctx, "c_longlong"),
199 IntKind::ULongLong => raw_type(ctx, "c_ulonglong"),
200 IntKind::WChar => {
201 let layout =
202 layout.expect("Couldn't compute wchar_t's layout?");
203 Layout::known_type_for_size(layout.size)
204 .expect("Non-representable wchar_t?")
205 }
206
207 IntKind::I8 => syn::parse_quote! { i8 },
208 IntKind::U8 => syn::parse_quote! { u8 },
209 IntKind::I16 => syn::parse_quote! { i16 },
210 IntKind::U16 => syn::parse_quote! { u16 },
211 IntKind::I32 => syn::parse_quote! { i32 },
212 IntKind::U32 => syn::parse_quote! { u32 },
213 IntKind::I64 => syn::parse_quote! { i64 },
214 IntKind::U64 => syn::parse_quote! { u64 },
215 IntKind::Custom { name, .. } => {
216 syn::parse_str(name).expect("Invalid integer type.")
217 }
218 IntKind::U128 => {
219 if true {
220 syn::parse_quote! { u128 }
221 } else {
222 syn::parse_quote! { [u64; 2] }
225 }
226 }
227 IntKind::I128 => {
228 if true {
229 syn::parse_quote! { i128 }
230 } else {
231 syn::parse_quote! { [u64; 2] }
232 }
233 }
234 }
235 }
236
237 pub(crate) fn float_kind_rust_type(
238 ctx: &BindgenContext,
239 fk: FloatKind,
240 layout: Option<Layout>,
241 ) -> syn::Type {
242 match (fk, ctx.options().convert_floats) {
247 (FloatKind::Float16, _) => {
248 ctx.generated_bindgen_float16();
250 if ctx.options().enable_cxx_namespaces {
251 syn::parse_quote! { root::__BindgenFloat16 }
252 } else {
253 syn::parse_quote! { __BindgenFloat16 }
254 }
255 }
256 (FloatKind::Float, true) => syn::parse_quote! { f32 },
257 (FloatKind::Double, true) => syn::parse_quote! { f64 },
258 (FloatKind::Float, false) => raw_type(ctx, "c_float"),
259 (FloatKind::Double, false) => raw_type(ctx, "c_double"),
260 (FloatKind::LongDouble, _) => {
261 if let Some(layout) = layout {
262 match layout.size {
263 4 => syn::parse_quote! { f32 },
264 8 => syn::parse_quote! { f64 },
265 _ => super::integer_type(layout)
268 .unwrap_or(syn::parse_quote! { f64 }),
269 }
270 } else {
271 debug_assert!(
272 false,
273 "How didn't we know the layout for a primitive type?"
274 );
275 syn::parse_quote! { f64 }
276 }
277 }
278 (FloatKind::Float128, _) => {
279 if true {
280 syn::parse_quote! { u128 }
281 } else {
282 syn::parse_quote! { [u64; 2] }
283 }
284 }
285 }
286 }
287
288 pub(crate) fn int_expr(val: i64) -> TokenStream {
289 let val = proc_macro2::Literal::i64_unsuffixed(val);
291 quote!(#val)
292 }
293
294 pub(crate) fn uint_expr(val: u64) -> TokenStream {
295 let val = proc_macro2::Literal::u64_unsuffixed(val);
297 quote!(#val)
298 }
299
300 pub(crate) fn cstr_expr(mut string: String) -> TokenStream {
301 string.push('\0');
302 let b = proc_macro2::Literal::byte_string(string.as_bytes());
303 quote! {
304 #b
305 }
306 }
307
308 pub(crate) fn float_expr(
309 ctx: &BindgenContext,
310 f: f64,
311 ) -> Result<TokenStream, ()> {
312 if f.is_finite() {
313 let val = proc_macro2::Literal::f64_unsuffixed(f);
314
315 return Ok(quote!(#val));
316 }
317
318 let prefix = ctx.trait_prefix();
319 let rust_target = ctx.options().rust_target;
320
321 if f.is_nan() {
322 #[allow(deprecated)]
324 let tokens = if rust_target >= RustTarget::Stable_1_43 {
325 quote! {
326 f64::NAN
327 }
328 } else {
329 quote! {
330 ::#prefix::f64::NAN
331 }
332 };
333 return Ok(tokens);
334 }
335
336 if f.is_infinite() {
337 let tokens = if f.is_sign_positive() {
338 #[allow(deprecated)]
340 if rust_target >= RustTarget::Stable_1_43 {
341 quote! {
342 f64::INFINITY
343 }
344 } else {
345 quote! {
346 ::#prefix::f64::INFINITY
347 }
348 }
349 } else {
350 #[allow(deprecated)]
352 if rust_target >= RustTarget::Stable_1_43 {
354 quote! {
355 f64::NEG_INFINITY
356 }
357 } else {
358 quote! {
359 ::#prefix::f64::NEG_INFINITY
360 }
361 }
362 };
363 return Ok(tokens);
364 }
365
366 warn!("Unknown non-finite float number: {f:?}");
367 Err(())
368 }
369
370 pub(crate) fn arguments_from_signature(
371 signature: &FunctionSig,
372 ctx: &BindgenContext,
373 ) -> Vec<TokenStream> {
374 let mut unnamed_arguments = 0;
375 signature
376 .argument_types()
377 .iter()
378 .map(|&(ref name, _ty)| {
379 let name = if let Some(ref name) = *name {
380 ctx.rust_ident(name)
381 } else {
382 unnamed_arguments += 1;
383 ctx.rust_ident(format!("arg{unnamed_arguments}"))
384 };
385 quote! { #name }
386 })
387 .collect()
388 }
389}