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