//! Helpers for code generation that don't need macro expansion. use aster; use ir::layout::Layout; use syntax::ast; use syntax::ptr::P; pub mod attributes { use aster; use syntax::ast; pub fn repr(which: &str) -> ast::Attribute { aster::AstBuilder::new().attr().list("repr").words(&[which]).build() } pub fn repr_list(which_ones: &[&str]) -> ast::Attribute { aster::AstBuilder::new().attr().list("repr").words(which_ones).build() } pub fn derives(which_ones: &[&str]) -> ast::Attribute { aster::AstBuilder::new().attr().list("derive").words(which_ones).build() } pub fn inline() -> ast::Attribute { aster::AstBuilder::new().attr().word("inline") } pub fn doc(comment: &str) -> ast::Attribute { aster::AstBuilder::new().attr().doc(comment) } pub fn link_name(name: &str) -> ast::Attribute { aster::AstBuilder::new().attr().name_value("link_name").str(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 struct BlobTyBuilder { layout: Layout, } impl BlobTyBuilder { pub fn new(layout: Layout) -> Self { BlobTyBuilder { layout: layout, } } pub fn build(self) -> P { let opaque = self.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 data_len = opaque.array_size().unwrap_or(self.layout.size); let inner_ty = aster::AstBuilder::new().ty().path().id(ty_name).build(); if data_len == 1 { inner_ty } else { aster::ty::TyBuilder::new().array(data_len).build(inner_ty) } } } pub mod ast_ty { use aster; use ir::context::BindgenContext; use ir::function::FunctionSig; use ir::ty::FloatKind; use syntax::ast; use syntax::ptr::P; pub fn raw_type(ctx: &BindgenContext, name: &str) -> P { let ident = ctx.rust_ident_raw(&name); match ctx.options().ctypes_prefix { Some(ref prefix) => { let prefix = ctx.rust_ident_raw(prefix); quote_ty!(ctx.ext_cx(), $prefix::$ident) } None => quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident), } } pub fn float_kind_rust_type(ctx: &BindgenContext, fk: FloatKind) -> P { // 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) => aster::ty::TyBuilder::new().f32(), (FloatKind::Double, true) | (FloatKind::LongDouble, true) => aster::ty::TyBuilder::new().f64(), (FloatKind::Float, false) => raw_type(ctx, "c_float"), (FloatKind::Double, false) | (FloatKind::LongDouble, false) => raw_type(ctx, "c_double"), (FloatKind::Float128, _) => { aster::ty::TyBuilder::new().array(16).u8() } } } pub fn int_expr(val: i64) -> P { use std::i64; let expr = aster::AstBuilder::new().expr(); // This is not representable as an i64 if it's negative, so we // special-case it. // // Fix in aster incoming. if val == i64::MIN { expr.neg().uint(1u64 << 63) } else { expr.int(val) } } pub fn bool_expr(val: bool) -> P { aster::AstBuilder::new().expr().bool(val) } pub fn byte_array_expr(bytes: &[u8]) -> P { let mut vec = Vec::with_capacity(bytes.len() + 1); for byte in bytes { vec.push(int_expr(*byte as i64)); } vec.push(int_expr(0)); let kind = ast::ExprKind::Vec(vec); aster::AstBuilder::new().expr().build_expr_kind(kind) } pub fn cstr_expr(mut string: String) -> P { string.push('\0'); aster::AstBuilder::new() .expr() .build_lit(aster::AstBuilder::new().lit().byte_str(string)) } pub fn float_expr(f: f64) -> P { use aster::symbol::ToSymbol; let mut string = f.to_string(); // So it gets properly recognised as a floating point constant. if !string.contains('.') { string.push('.'); } let kind = ast::LitKind::FloatUnsuffixed(string.as_str().to_symbol()); aster::AstBuilder::new().expr().lit().build_lit(kind) } pub fn arguments_from_signature(signature: &FunctionSig, ctx: &BindgenContext) -> Vec> { // TODO: We need to keep in sync the argument names, so we should unify // this with the other loop that decides them. let mut unnamed_arguments = 0; signature.argument_types() .iter() .map(|&(ref name, _ty)| { let arg_name = match *name { Some(ref name) => ctx.rust_mangle(name).into_owned(), None => { unnamed_arguments += 1; format!("arg{}", unnamed_arguments) } }; aster::expr::ExprBuilder::new().id(arg_name) }) .collect::>() } }