summaryrefslogtreecommitdiff
path: root/libbindgen/src/codegen/helpers.rs
blob: 6e5a6f0e31cdda8ca356aded19d874b13d06dc7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! 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<ast::Ty> {
        use std::cmp;

        let ty_name = match self.layout.align {
            8 => "u64",
            4 => "u32",
            2 => "u16",
            1 | _ => "u8",
        };
        let data_len = if ty_name == "u8" {
            self.layout.size
        } else {
            self.layout.size / cmp::max(self.layout.align, 1)
        };

        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::ty::FloatKind;
    use syntax::ast;
    use syntax::ptr::P;

    pub fn raw_type(ctx: &BindgenContext, name: &str) -> P<ast::Ty> {
        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<ast::Ty> {
        macro_rules! raw {
            ($ty: ident) => {
                raw_type(ctx, stringify!($ty))
            }
        }
        // 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!(c_float),
            (FloatKind::Double, false) |
            (FloatKind::LongDouble, false) => raw!(c_double),
            (FloatKind::Float128, _) => {
                aster::ty::TyBuilder::new().array(16).u8()
            }
        }
    }

    pub fn int_expr(val: i64) -> P<ast::Expr> {
        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)
        }
    }
}