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 | |
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. |
77 | 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`. |
108 | pub 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`. |
118 | pub 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 | |
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 | |
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 | |