1//! Helpers for code generation that don't need macro expansion.
2
3use crate::ir::context::BindgenContext;
4use crate::ir::layout::Layout;
5use proc_macro2::{Ident, Span, TokenStream};
6use quote::TokenStreamExt;
7
8pub mod attributes {
9 use proc_macro2::{Ident, Span, TokenStream};
10 use std::str::FromStr;
11
12 pub fn repr(which: &str) -> TokenStream {
13 let which = Ident::new(which, Span::call_site());
14 quote! {
15 #[repr( #which )]
16 }
17 }
18
19 pub fn repr_list(which_ones: &[&str]) -> TokenStream {
20 let which_ones = which_ones
21 .iter()
22 .cloned()
23 .map(|one| TokenStream::from_str(one).expect("repr to be valid"));
24 quote! {
25 #[repr( #( #which_ones ),* )]
26 }
27 }
28
29 pub fn derives(which_ones: &[&str]) -> TokenStream {
30 let which_ones = which_ones
31 .iter()
32 .cloned()
33 .map(|one| TokenStream::from_str(one).expect("derive to be valid"));
34 quote! {
35 #[derive( #( #which_ones ),* )]
36 }
37 }
38
39 pub fn inline() -> TokenStream {
40 quote! {
41 #[inline]
42 }
43 }
44
45 pub fn must_use() -> TokenStream {
46 quote! {
47 #[must_use]
48 }
49 }
50
51 pub fn non_exhaustive() -> TokenStream {
52 quote! {
53 #[non_exhaustive]
54 }
55 }
56
57 pub fn doc(comment: String) -> TokenStream {
58 if comment.is_empty() {
59 quote!()
60 } else {
61 quote!(#[doc = #comment])
62 }
63 }
64
65 pub fn link_name(name: &str) -> TokenStream {
66 // LLVM mangles the name by default but it's already mangled.
67 // Prefixing the name with \u{1} should tell LLVM to not mangle it.
68 let name = format!("\u{1}{}", name);
69 quote! {
70 #[link_name = #name]
71 }
72 }
73}
74
75/// Generates a proper type for a field or type with a given `Layout`, that is,
76/// a type with the correct size and alignment restrictions.
77pub fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream {
78 let opaque = layout.opaque();
79
80 // FIXME(emilio, #412): We fall back to byte alignment, but there are
81 // some things that legitimately are more than 8-byte aligned.
82 //
83 // Eventually we should be able to `unwrap` here, but...
84 let ty_name = match opaque.known_rust_type_for_array(ctx) {
85 Some(ty) => ty,
86 None => {
87 warn!("Found unknown alignment on code generation!");
88 "u8"
89 }
90 };
91
92 let ty_name = Ident::new(ty_name, Span::call_site());
93
94 let data_len = opaque.array_size(ctx).unwrap_or(layout.size);
95
96 if data_len == 1 {
97 quote! {
98 #ty_name
99 }
100 } else {
101 quote! {
102 [ #ty_name ; #data_len ]
103 }
104 }
105}
106
107/// Integer type of the same size as the given `Layout`.
108pub fn integer_type(
109 ctx: &BindgenContext,
110 layout: Layout,
111) -> Option<TokenStream> {
112 let name: &str = Layout::known_type_for_size(ctx, layout.size)?;
113 let name: Ident = Ident::new(string:name, Span::call_site());
114 Some(quote! { #name })
115}
116
117/// Generates a bitfield allocation unit type for a type with the given `Layout`.
118pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream {
119 let mut tokens: TokenStream = quote! {};
120
121 if ctx.options().enable_cxx_namespaces {
122 tokens.append_all(iter:quote! { root:: });
123 }
124
125 let size: usize = layout.size;
126 tokens.append_all(iter:quote! {
127 __BindgenBitfieldUnit<[u8; #size]>
128 });
129
130 tokens
131}
132
133pub mod ast_ty {
134 use crate::ir::context::BindgenContext;
135 use crate::ir::function::FunctionSig;
136 use crate::ir::layout::Layout;
137 use crate::ir::ty::FloatKind;
138 use proc_macro2::{self, TokenStream};
139 use std::str::FromStr;
140
141 pub fn c_void(ctx: &BindgenContext) -> TokenStream {
142 // ctypes_prefix takes precedence
143 match ctx.options().ctypes_prefix {
144 Some(ref prefix) => {
145 let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
146 quote! {
147 #prefix::c_void
148 }
149 }
150 None => {
151 if ctx.options().use_core &&
152 ctx.options().rust_features.core_ffi_c_void
153 {
154 quote! { ::core::ffi::c_void }
155 } else {
156 quote! { ::std::os::raw::c_void }
157 }
158 }
159 }
160 }
161
162 pub fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream {
163 let ident = ctx.rust_ident_raw(name);
164 match ctx.options().ctypes_prefix {
165 Some(ref prefix) => {
166 let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
167 quote! {
168 #prefix::#ident
169 }
170 }
171 None => {
172 if ctx.options().use_core &&
173 ctx.options().rust_features().core_ffi_c
174 {
175 quote! {
176 ::core::ffi::#ident
177 }
178 } else {
179 quote! {
180 ::std::os::raw::#ident
181 }
182 }
183 }
184 }
185 }
186
187 pub fn float_kind_rust_type(
188 ctx: &BindgenContext,
189 fk: FloatKind,
190 layout: Option<Layout>,
191 ) -> TokenStream {
192 // TODO: we probably should take the type layout into account more
193 // often?
194 //
195 // Also, maybe this one shouldn't be the default?
196 match (fk, ctx.options().convert_floats) {
197 (FloatKind::Float, true) => quote! { f32 },
198 (FloatKind::Double, true) => quote! { f64 },
199 (FloatKind::Float, false) => raw_type(ctx, "c_float"),
200 (FloatKind::Double, false) => raw_type(ctx, "c_double"),
201 (FloatKind::LongDouble, _) => {
202 match layout {
203 Some(layout) => {
204 match layout.size {
205 4 => quote! { f32 },
206 8 => quote! { f64 },
207 // TODO(emilio): If rust ever gains f128 we should
208 // use it here and below.
209 _ => super::integer_type(ctx, layout)
210 .unwrap_or(quote! { f64 }),
211 }
212 }
213 None => {
214 debug_assert!(
215 false,
216 "How didn't we know the layout for a primitive type?"
217 );
218 quote! { f64 }
219 }
220 }
221 }
222 (FloatKind::Float128, _) => {
223 if ctx.options().rust_features.i128_and_u128 {
224 quote! { u128 }
225 } else {
226 quote! { [u64; 2] }
227 }
228 }
229 }
230 }
231
232 pub fn int_expr(val: i64) -> TokenStream {
233 // Don't use quote! { #val } because that adds the type suffix.
234 let val = proc_macro2::Literal::i64_unsuffixed(val);
235 quote!(#val)
236 }
237
238 pub fn uint_expr(val: u64) -> TokenStream {
239 // Don't use quote! { #val } because that adds the type suffix.
240 let val = proc_macro2::Literal::u64_unsuffixed(val);
241 quote!(#val)
242 }
243
244 pub fn byte_array_expr(bytes: &[u8]) -> TokenStream {
245 let mut bytes: Vec<_> = bytes.to_vec();
246 bytes.push(0);
247 quote! { [ #(#bytes),* ] }
248 }
249
250 pub fn cstr_expr(mut string: String) -> TokenStream {
251 string.push('\0');
252 let b = proc_macro2::Literal::byte_string(string.as_bytes());
253 quote! {
254 #b
255 }
256 }
257
258 pub fn float_expr(ctx: &BindgenContext, f: f64) -> Result<TokenStream, ()> {
259 if f.is_finite() {
260 let val = proc_macro2::Literal::f64_unsuffixed(f);
261
262 return Ok(quote!(#val));
263 }
264
265 let prefix = ctx.trait_prefix();
266
267 if f.is_nan() {
268 return Ok(quote! {
269 ::#prefix::f64::NAN
270 });
271 }
272
273 if f.is_infinite() {
274 return Ok(if f.is_sign_positive() {
275 quote! {
276 ::#prefix::f64::INFINITY
277 }
278 } else {
279 quote! {
280 ::#prefix::f64::NEG_INFINITY
281 }
282 });
283 }
284
285 warn!("Unknown non-finite float number: {:?}", f);
286 Err(())
287 }
288
289 pub fn arguments_from_signature(
290 signature: &FunctionSig,
291 ctx: &BindgenContext,
292 ) -> Vec<TokenStream> {
293 let mut unnamed_arguments = 0;
294 signature
295 .argument_types()
296 .iter()
297 .map(|&(ref name, _ty)| match *name {
298 Some(ref name) => {
299 let name = ctx.rust_ident(name);
300 quote! { #name }
301 }
302 None => {
303 unnamed_arguments += 1;
304 let name =
305 ctx.rust_ident(format!("arg{}", unnamed_arguments));
306 quote! { #name }
307 }
308 })
309 .collect()
310 }
311}
312