• 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| 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 size = layout.size;
124     tokens.append_all(quote! {
125         __BindgenBitfieldUnit<[u8; #size]>
126     });
127 
128     tokens
129 }
130 
131 pub mod ast_ty {
132     use crate::ir::context::BindgenContext;
133     use crate::ir::function::FunctionSig;
134     use crate::ir::layout::Layout;
135     use crate::ir::ty::FloatKind;
136     use proc_macro2::{self, TokenStream};
137     use std::str::FromStr;
138 
c_void(ctx: &BindgenContext) -> TokenStream139     pub fn c_void(ctx: &BindgenContext) -> TokenStream {
140         // ctypes_prefix takes precedence
141         match ctx.options().ctypes_prefix {
142             Some(ref prefix) => {
143                 let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
144                 quote! {
145                     #prefix::c_void
146                 }
147             }
148             None => {
149                 if ctx.options().use_core &&
150                     ctx.options().rust_features.core_ffi_c_void
151                 {
152                     quote! { ::core::ffi::c_void }
153                 } else {
154                     quote! { ::std::os::raw::c_void }
155                 }
156             }
157         }
158     }
159 
raw_type(ctx: &BindgenContext, name: &str) -> TokenStream160     pub fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream {
161         let ident = ctx.rust_ident_raw(name);
162         match ctx.options().ctypes_prefix {
163             Some(ref prefix) => {
164                 let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
165                 quote! {
166                     #prefix::#ident
167                 }
168             }
169             None => quote! {
170                 ::std::os::raw::#ident
171             },
172         }
173     }
174 
float_kind_rust_type( ctx: &BindgenContext, fk: FloatKind, layout: Option<Layout>, ) -> TokenStream175     pub fn float_kind_rust_type(
176         ctx: &BindgenContext,
177         fk: FloatKind,
178         layout: Option<Layout>,
179     ) -> TokenStream {
180         // TODO: we probably should take the type layout into account more
181         // often?
182         //
183         // Also, maybe this one shouldn't be the default?
184         match (fk, ctx.options().convert_floats) {
185             (FloatKind::Float, true) => quote! { f32 },
186             (FloatKind::Double, true) => quote! { f64 },
187             (FloatKind::Float, false) => raw_type(ctx, "c_float"),
188             (FloatKind::Double, false) => raw_type(ctx, "c_double"),
189             (FloatKind::LongDouble, _) => {
190                 match layout {
191                     Some(layout) => {
192                         match layout.size {
193                             4 => quote! { f32 },
194                             8 => quote! { f64 },
195                             // TODO(emilio): If rust ever gains f128 we should
196                             // use it here and below.
197                             _ => super::integer_type(ctx, layout)
198                                 .unwrap_or(quote! { f64 }),
199                         }
200                     }
201                     None => {
202                         debug_assert!(
203                             false,
204                             "How didn't we know the layout for a primitive type?"
205                         );
206                         quote! { f64 }
207                     }
208                 }
209             }
210             (FloatKind::Float128, _) => {
211                 if ctx.options().rust_features.i128_and_u128 {
212                     quote! { u128 }
213                 } else {
214                     quote! { [u64; 2] }
215                 }
216             }
217         }
218     }
219 
int_expr(val: i64) -> TokenStream220     pub fn int_expr(val: i64) -> TokenStream {
221         // Don't use quote! { #val } because that adds the type suffix.
222         let val = proc_macro2::Literal::i64_unsuffixed(val);
223         quote!(#val)
224     }
225 
uint_expr(val: u64) -> TokenStream226     pub fn uint_expr(val: u64) -> TokenStream {
227         // Don't use quote! { #val } because that adds the type suffix.
228         let val = proc_macro2::Literal::u64_unsuffixed(val);
229         quote!(#val)
230     }
231 
byte_array_expr(bytes: &[u8]) -> TokenStream232     pub fn byte_array_expr(bytes: &[u8]) -> TokenStream {
233         let mut bytes: Vec<_> = bytes.iter().cloned().collect();
234         bytes.push(0);
235         quote! { [ #(#bytes),* ] }
236     }
237 
cstr_expr(mut string: String) -> TokenStream238     pub fn cstr_expr(mut string: String) -> TokenStream {
239         string.push('\0');
240         let b = proc_macro2::Literal::byte_string(&string.as_bytes());
241         quote! {
242             #b
243         }
244     }
245 
float_expr(ctx: &BindgenContext, f: f64) -> Result<TokenStream, ()>246     pub fn float_expr(ctx: &BindgenContext, f: f64) -> Result<TokenStream, ()> {
247         if f.is_finite() {
248             let val = proc_macro2::Literal::f64_unsuffixed(f);
249 
250             return Ok(quote!(#val));
251         }
252 
253         let prefix = ctx.trait_prefix();
254 
255         if f.is_nan() {
256             return Ok(quote! {
257                 ::#prefix::f64::NAN
258             });
259         }
260 
261         if f.is_infinite() {
262             return Ok(if f.is_sign_positive() {
263                 quote! {
264                     ::#prefix::f64::INFINITY
265                 }
266             } else {
267                 quote! {
268                     ::#prefix::f64::NEG_INFINITY
269                 }
270             });
271         }
272 
273         warn!("Unknown non-finite float number: {:?}", f);
274         return Err(());
275     }
276 
arguments_from_signature( signature: &FunctionSig, ctx: &BindgenContext, ) -> Vec<TokenStream>277     pub fn arguments_from_signature(
278         signature: &FunctionSig,
279         ctx: &BindgenContext,
280     ) -> Vec<TokenStream> {
281         let mut unnamed_arguments = 0;
282         signature
283             .argument_types()
284             .iter()
285             .map(|&(ref name, _ty)| match *name {
286                 Some(ref name) => {
287                     let name = ctx.rust_ident(name);
288                     quote! { #name }
289                 }
290                 None => {
291                     unnamed_arguments += 1;
292                     let name =
293                         ctx.rust_ident(format!("arg{}", unnamed_arguments));
294                     quote! { #name }
295                 }
296             })
297             .collect()
298     }
299 }
300