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