//! Helpers for code generation that don't need macro expansion. use ir::layout::Layout; use quote; pub mod attributes { use quote; pub fn repr(which: &str) -> quote::Tokens { let which = quote::Ident::new(which); quote! { #[repr( #which )] } } pub fn repr_list(which_ones: &[&str]) -> quote::Tokens { let which_ones = which_ones.iter().cloned().map(quote::Ident::new); quote! { #[repr( #( #which_ones ),* )] } } pub fn derives(which_ones: &[&str]) -> quote::Tokens { let which_ones = which_ones.iter().cloned().map(quote::Ident::new); quote! { #[derive( #( #which_ones ),* )] } } pub fn inline() -> quote::Tokens { quote! { #[inline] } } pub fn doc(comment: String) -> quote::Tokens { // Doc comments are already preprocessed into nice `///` formats by the // time they get here. Just make sure that we have newlines around it so // that nothing else gets wrapped into the comment. let mut tokens = quote! {}; tokens.append("\n"); tokens.append(comment); tokens.append("\n"); tokens } pub fn link_name(name: &str) -> quote::Tokens { // LLVM mangles the name by default but it's already mangled. // Prefixing the name with \u{1} should tell LLVM to not mangle it. let name = format!("\u{1}{}", name); quote! { #[link_name = #name] } } } /// Generates a proper type for a field or type with a given `Layout`, that is, /// a type with the correct size and alignment restrictions. pub fn blob(layout: Layout) -> quote::Tokens { let opaque = layout.opaque(); // FIXME(emilio, #412): We fall back to byte alignment, but there are // some things that legitimately are more than 8-byte aligned. // // Eventually we should be able to `unwrap` here, but... let ty_name = match opaque.known_rust_type_for_array() { Some(ty) => ty, None => { warn!("Found unknown alignment on code generation!"); "u8" } }; let ty_name = quote::Ident::new(ty_name); let data_len = opaque.array_size().unwrap_or(layout.size); if data_len == 1 { quote! { #ty_name } } else { quote! { [ #ty_name ; #data_len ] } } } pub mod ast_ty { use ir::context::BindgenContext; use ir::function::FunctionSig; use ir::ty::FloatKind; use quote; pub fn raw_type(ctx: &BindgenContext, name: &str) -> quote::Tokens { let ident = ctx.rust_ident_raw(name); match ctx.options().ctypes_prefix { Some(ref prefix) => { let prefix = ctx.rust_ident_raw(prefix.as_str()); quote! { #prefix::#ident } } None => quote! { ::std::os::raw::#ident }, } } pub fn float_kind_rust_type( ctx: &BindgenContext, fk: FloatKind, ) -> quote::Tokens { // TODO: we probably should just take the type layout into // account? // // Also, maybe this one shouldn't be the default? // // FIXME: `c_longdouble` doesn't seem to be defined in some // systems, so we use `c_double` directly. match (fk, ctx.options().convert_floats) { (FloatKind::Float, true) => quote! { f32 }, (FloatKind::Double, true) | (FloatKind::LongDouble, true) => quote! { f64 }, (FloatKind::Float, false) => raw_type(ctx, "c_float"), (FloatKind::Double, false) | (FloatKind::LongDouble, false) => raw_type(ctx, "c_double"), (FloatKind::Float128, _) => quote! { [u8; 16] }, } } pub fn int_expr(val: i64) -> quote::Tokens { // Don't use quote! { #val } because that adds the type suffix. let mut tokens = quote! {}; tokens.append(val.to_string()); tokens } pub fn uint_expr(val: u64) -> quote::Tokens { // Don't use quote! { #val } because that adds the type suffix. let mut tokens = quote! {}; tokens.append(val.to_string()); tokens } /// Returns hex representation of the given value. pub fn hex_expr(val: u64) -> quote::Tokens { let mut tokens = quote! {}; tokens.append(format!("{:#x}", val)); tokens } pub fn byte_array_expr(bytes: &[u8]) -> quote::Tokens { let mut bytes: Vec<_> = bytes.iter().cloned().collect(); bytes.push(0); quote! { #bytes } } pub fn cstr_expr(mut string: String) -> quote::Tokens { string.push('\0'); let b = quote::ByteStr(&string); quote! { #b } } pub fn float_expr( ctx: &BindgenContext, f: f64, ) -> Result { if f.is_finite() { let mut string = f.to_string(); // So it gets properly recognised as a floating point constant. if !string.contains('.') { string.push('.'); } let mut tokens = quote! {}; tokens.append(string); return Ok(tokens); } let prefix = ctx.trait_prefix(); if f.is_nan() { return Ok(quote! { ::#prefix::f64::NAN }); } if f.is_infinite() { return Ok(if f.is_sign_positive() { quote! { ::#prefix::f64::INFINITY } } else { quote! { ::#prefix::f64::NEG_INFINITY } }); } warn!("Unknown non-finite float number: {:?}", f); return Err(()); } pub fn arguments_from_signature( signature: &FunctionSig, ctx: &BindgenContext, ) -> Vec { let mut unnamed_arguments = 0; signature .argument_types() .iter() .map(|&(ref name, _ty)| { match *name { Some(ref name) => { let name = ctx.rust_ident(name); quote! { #name } } None => { unnamed_arguments += 1; let name = ctx.rust_ident(format!("arg{}", unnamed_arguments)); quote! { #name } } } }) .collect() } }