• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Helpers for code generation that don't need macro expansion.
2 
3 use crate::ir::context::BindgenContext;
4 use crate::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| TokenStream::from_str(one).expect("derive to be valid"));
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         if comment.is_empty() {
59             quote!()
60         } else {
61             quote!(#[doc = #comment])
62         }
63     }
64 
link_name(name: &str) -> TokenStream65     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.
blob(ctx: &BindgenContext, layout: Layout) -> TokenStream77 pub 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`.
integer_type( ctx: &BindgenContext, layout: Layout, ) -> Option<TokenStream>108 pub fn integer_type(
109     ctx: &BindgenContext,
110     layout: Layout,
111 ) -> Option<TokenStream> {
112     let name = Layout::known_type_for_size(ctx, layout.size)?;
113     let name = Ident::new(name, Span::call_site());
114     Some(quote! { #name })
115 }
116 
117 /// Generates a bitfield allocation unit type for a type with the given `Layout`.
bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream118 pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream {
119     let mut tokens = quote! {};
120 
121     if ctx.options().enable_cxx_namespaces {
122         tokens.append_all(quote! { root:: });
123     }
124 
125     let size = layout.size;
126     tokens.append_all(quote! {
127         __BindgenBitfieldUnit<[u8; #size]>
128     });
129 
130     tokens
131 }
132 
133 pub 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 
c_void(ctx: &BindgenContext) -> TokenStream141     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 
raw_type(ctx: &BindgenContext, name: &str) -> TokenStream162     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 
float_kind_rust_type( ctx: &BindgenContext, fk: FloatKind, layout: Option<Layout>, ) -> TokenStream187     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 
int_expr(val: i64) -> TokenStream232     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 
uint_expr(val: u64) -> TokenStream238     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 
byte_array_expr(bytes: &[u8]) -> TokenStream244     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 
cstr_expr(mut string: String) -> TokenStream250     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 
float_expr(ctx: &BindgenContext, f: f64) -> Result<TokenStream, ()>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 
arguments_from_signature( signature: &FunctionSig, ctx: &BindgenContext, ) -> Vec<TokenStream>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