Skip to content

Commit d38ffa5

Browse files
committed
Add support for const items
1 parent 598382f commit d38ffa5

File tree

11 files changed

+307
-16
lines changed

11 files changed

+307
-16
lines changed

compile-tests/constant.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const FOO: i32 = 10;
2+
const BAR: &'static libc::c_char = "hello world";
3+
4+
#[repr(C)]
5+
struct Foo {
6+
x: [i32; FOO],
7+
}
8+
9+
#[no_mangle]
10+
extern "C" fn root(x: Foo) { }

src/bindgen/bindings.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,27 @@ use std::path;
88
use std::fs;
99

1010
use bindgen::config::{Config, Language};
11-
use bindgen::ir::{ItemContainer, Function};
11+
use bindgen::ir::{Constant, ItemContainer, Function};
1212
use bindgen::monomorph::TemplateSpecialization;
1313
use bindgen::writer::{ListType, Source, SourceWriter};
1414

1515
pub struct Bindings {
1616
config: Config,
17+
constants: Vec<Constant>,
1718
items: Vec<ItemContainer>,
1819
functions: Vec<Function>,
1920
template_specializations: Vec<TemplateSpecialization>,
2021
}
2122

2223
impl Bindings {
2324
pub fn new(config: Config,
25+
constants: Vec<Constant>,
2426
items: Vec<ItemContainer>,
2527
functions: Vec<Function>,
2628
template_specializations: Vec<TemplateSpecialization>) -> Bindings {
2729
Bindings {
2830
config: config,
31+
constants: constants,
2932
items: items,
3033
functions: functions,
3134
template_specializations: template_specializations,
@@ -89,13 +92,20 @@ impl Bindings {
8992
self.open_namespaces(&mut out);
9093
}
9194

95+
for constant in &self.constants {
96+
out.new_line_if_not_start();
97+
constant.write(&self.config, &mut out);
98+
out.new_line();
99+
}
100+
92101
for item in &self.items {
93102
if item.deref().annotations().bool("no-export").unwrap_or(false) {
94103
continue;
95104
}
96105

97106
out.new_line_if_not_start();
98107
match item {
108+
&ItemContainer::Constant(ref x) => x.write(&self.config, &mut out),
99109
&ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
100110
&ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
101111
&ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),

src/bindgen/builder.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use syn;
88

99
use bindgen::cargo::Cargo;
1010
use bindgen::config::Config;
11-
use bindgen::ir::{AnnotationSet, Cfg, Documentation, Enum, Function};
11+
use bindgen::ir::{AnnotationSet, Cfg, Constant, Documentation, Enum, Function};
1212
use bindgen::ir::{ItemMap, OpaqueItem, Specialization, Struct, Typedef};
1313
use bindgen::library::Library;
1414
use bindgen::rust_lib;
@@ -80,6 +80,7 @@ impl LibraryBuilder {
8080
result.functions.sort_by(|x, y| x.name.cmp(&y.name));
8181

8282
Ok(Library::new(self.config,
83+
result.constants,
8384
result.enums,
8485
result.structs,
8586
result.opaque_items,
@@ -91,6 +92,7 @@ impl LibraryBuilder {
9192

9293
#[derive(Debug, Clone)]
9394
struct LibraryParseResult {
95+
constants: ItemMap<Constant>,
9496
enums: ItemMap<Enum>,
9597
structs: ItemMap<Struct>,
9698
opaque_items: ItemMap<OpaqueItem>,
@@ -103,6 +105,7 @@ impl LibraryParseResult {
103105
fn new() -> LibraryParseResult {
104106
LibraryParseResult {
105107
enums: ItemMap::new(),
108+
constants: ItemMap::new(),
106109
structs: ItemMap::new(),
107110
opaque_items: ItemMap::new(),
108111
typedefs: ItemMap::new(),
@@ -168,6 +171,14 @@ impl LibraryParseResult {
168171
decl,
169172
abi);
170173
}
174+
syn::ItemKind::Const(ref ty, ref expr) => {
175+
self.load_syn_const(binding_crate_name,
176+
crate_name,
177+
mod_cfg,
178+
item,
179+
ty,
180+
expr);
181+
}
171182
syn::ItemKind::Struct(ref variant, ref generics) => {
172183
self.load_syn_struct(crate_name, mod_cfg, item, variant, generics);
173184
}
@@ -275,6 +286,42 @@ impl LibraryParseResult {
275286
}
276287
}
277288

289+
/// Loads a `const` declaration
290+
fn load_syn_const(&mut self,
291+
binding_crate_name: &str,
292+
crate_name: &str,
293+
mod_cfg: &Option<Cfg>,
294+
item: &syn::Item,
295+
ty: &syn::Ty,
296+
expr: &syn::Expr) {
297+
if crate_name != binding_crate_name {
298+
info!("Skip {}::{} - (const's outside of the binding crate are not used).",
299+
crate_name,
300+
&item.ident);
301+
return;
302+
}
303+
304+
let const_name = item.ident.to_string();
305+
306+
match Constant::load(const_name.clone(),
307+
ty,
308+
expr,
309+
&item.attrs,
310+
mod_cfg) {
311+
Ok(constant) => {
312+
info!("Take {}::{}.", crate_name, &item.ident);
313+
314+
self.constants.try_insert(constant);
315+
}
316+
Err(msg) => {
317+
warn!("Skip {}::{} - ({})",
318+
crate_name,
319+
&item.ident,
320+
msg);
321+
}
322+
}
323+
}
324+
278325
/// Loads a `struct` declaration
279326
fn load_syn_struct(&mut self,
280327
crate_name: &str,

src/bindgen/cdecl.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use bindgen::writer::SourceWriter;
1313

1414
enum CDeclarator {
1515
Ptr(bool),
16-
Array(u64),
16+
Array(String),
1717
Func(Vec<(Option<String>, CDecl)>, bool),
1818
}
1919

@@ -92,8 +92,8 @@ impl CDecl {
9292
self.declarators.push(CDeclarator::Ptr(is_const));
9393
self.build_type(t, false);
9494
}
95-
&Type::Array(ref t, sz) => {
96-
self.declarators.push(CDeclarator::Array(sz));
95+
&Type::Array(ref t, ref constant) => {
96+
self.declarators.push(CDeclarator::Array(constant.clone()));
9797
self.build_type(t, false);
9898
}
9999
&Type::FuncPtr(ref ret, ref args) => {
@@ -164,11 +164,11 @@ impl CDecl {
164164
&CDeclarator::Ptr(..) => {
165165
last_was_pointer = true;
166166
},
167-
&CDeclarator::Array(sz) => {
167+
&CDeclarator::Array(ref constant) => {
168168
if last_was_pointer {
169169
out.write(")");
170170
}
171-
out.write(&format!("[{}]", sz));
171+
out.write(&format!("[{}]", constant));
172172

173173
last_was_pointer = false;
174174
},

src/bindgen/config.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ impl StructConfig {
217217
}
218218

219219
/// Settings to apply to generated enums.
220-
#[derive( Debug, Clone, Deserialize)]
220+
#[derive(Debug, Clone, Deserialize)]
221221
#[serde(rename_all = "snake_case")]
222222
#[serde(deny_unknown_fields)]
223223
#[serde(default)]
@@ -250,6 +250,24 @@ impl EnumConfig {
250250
}
251251
}
252252

253+
/// Settings to apply to generated constants.
254+
#[derive(Debug, Clone, Deserialize)]
255+
#[serde(rename_all = "snake_case")]
256+
#[serde(deny_unknown_fields)]
257+
#[serde(default)]
258+
pub struct ConstantConfig {
259+
/// Whether a generated constant can be a static const in C++ mode.
260+
pub allow_static_const: bool,
261+
}
262+
263+
impl Default for ConstantConfig {
264+
fn default() -> ConstantConfig {
265+
ConstantConfig {
266+
allow_static_const: true,
267+
}
268+
}
269+
}
270+
253271
/// Settings to apply when parsing.
254272
#[derive( Debug, Clone, Deserialize)]
255273
#[serde(rename_all = "snake_case")]
@@ -323,6 +341,8 @@ pub struct Config {
323341
/// The configuration options for enums
324342
#[serde(rename = "enum")]
325343
pub enumeration: EnumConfig,
344+
#[serde(rename = "const")]
345+
pub constant: ConstantConfig,
326346
// Preprocessor defines to use when generating #ifdef's for #[cfg]
327347
pub defines: HashMap<String, String>,
328348
/// Include doc comments from rust as documentation
@@ -347,6 +367,7 @@ impl Default for Config {
347367
function: FunctionConfig::default(),
348368
structure: StructConfig::default(),
349369
enumeration: EnumConfig::default(),
370+
constant: ConstantConfig::default(),
350371
defines: HashMap::new(),
351372
documentation: true,
352373
}

src/bindgen/ir/constant.rs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
use std::io::Write;
6+
use std::mem;
7+
8+
use syn;
9+
10+
use bindgen::config::{Config, Language};
11+
use bindgen::ir::{AnnotationSet, Cfg, Documentation, Item, ItemContainer, Specialization, Type};
12+
use bindgen::library::Library;
13+
use bindgen::writer::{Source, SourceWriter};
14+
15+
#[derive(Debug, Clone)]
16+
pub struct LiteralExpr(String);
17+
18+
impl LiteralExpr {
19+
pub fn load(expr: &syn::Expr) -> Result<LiteralExpr, String> {
20+
match &expr.node {
21+
&syn::ExprKind::Lit(syn::Lit::Str(ref text, ..)) => {
22+
Ok(LiteralExpr(format!("\"{}\"", text)))
23+
}
24+
&syn::ExprKind::Lit(syn::Lit::Byte(value)) => {
25+
Ok(LiteralExpr(format!("{}", value)))
26+
}
27+
&syn::ExprKind::Lit(syn::Lit::Char(value)) => {
28+
Ok(LiteralExpr(format!("{}", value)))
29+
}
30+
&syn::ExprKind::Lit(syn::Lit::Int(value, ref ty)) => {
31+
match ty {
32+
&syn::IntTy::Usize |
33+
&syn::IntTy::U8 |
34+
&syn::IntTy::U16 |
35+
&syn::IntTy::U32 |
36+
&syn::IntTy::U64 |
37+
&syn::IntTy::Unsuffixed => {
38+
Ok(LiteralExpr(format!("{}", value)))
39+
}
40+
&syn::IntTy::Isize |
41+
&syn::IntTy::I8 |
42+
&syn::IntTy::I16 |
43+
&syn::IntTy::I32 |
44+
&syn::IntTy::I64 => {
45+
unsafe {
46+
Ok(LiteralExpr(format!("{}", mem::transmute::<u64, i64>(value))))
47+
}
48+
}
49+
}
50+
}
51+
&syn::ExprKind::Lit(syn::Lit::Float(ref value, ref _ty)) => {
52+
Ok(LiteralExpr(format!("{}", value)))
53+
}
54+
&syn::ExprKind::Lit(syn::Lit::Bool(value)) => {
55+
Ok(LiteralExpr(format!("{}", value)))
56+
}
57+
_ => Err("Unsupported literal expression.".to_owned())
58+
}
59+
}
60+
}
61+
62+
#[derive(Debug, Clone)]
63+
pub struct Constant {
64+
pub name: String,
65+
pub ty: Type,
66+
pub value: LiteralExpr,
67+
pub cfg: Option<Cfg>,
68+
pub annotations: AnnotationSet,
69+
pub documentation: Documentation,
70+
}
71+
72+
73+
impl Constant {
74+
pub fn load(name: String,
75+
ty: &syn::Ty,
76+
expr: &syn::Expr,
77+
attrs: &Vec<syn::Attribute>,
78+
mod_cfg: &Option<Cfg>) -> Result<Constant, String>
79+
{
80+
let ty = Type::load(ty)?;
81+
82+
if ty.is_none() {
83+
return Err("Cannot have a zero sized const definition.".to_owned());
84+
}
85+
86+
let ty = ty.unwrap();
87+
88+
if !ty.is_primitive_or_ptr_primitive() {
89+
return Err("Cannot have a non primitive const definition.".to_owned());
90+
}
91+
92+
Ok(Constant {
93+
name: name,
94+
ty: ty,
95+
value: LiteralExpr::load(expr)?,
96+
cfg: Cfg::append(mod_cfg, Cfg::load(attrs)),
97+
annotations: AnnotationSet::load(attrs)?,
98+
documentation: Documentation::load(attrs),
99+
})
100+
}
101+
}
102+
103+
impl Item for Constant {
104+
fn name(&self) -> &str {
105+
&self.name
106+
}
107+
108+
fn cfg(&self) -> &Option<Cfg> {
109+
&self.cfg
110+
}
111+
112+
fn annotations(&self) -> &AnnotationSet {
113+
&self.annotations
114+
}
115+
116+
fn annotations_mut(&mut self) -> &mut AnnotationSet {
117+
&mut self.annotations
118+
}
119+
120+
fn container(&self) -> ItemContainer {
121+
ItemContainer::Constant(self.clone())
122+
}
123+
124+
fn specialize(&self, _library: &Library, _aliasee: &Specialization) -> Result<Box<Item>, String> {
125+
unreachable!();
126+
}
127+
}
128+
129+
impl Source for Constant {
130+
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
131+
if config.constant.allow_static_const &&
132+
config.language == Language::Cxx
133+
{
134+
if let Type::ConstPtr(..) = self.ty {
135+
out.write("static ");
136+
} else {
137+
out.write("static const ");
138+
}
139+
self.ty.write(config, out);
140+
out.write(&format!(" {} = {};", self.name, self.value.0))
141+
} else {
142+
out.write(&format!("#define {} {}", self.name, self.value.0))
143+
}
144+
}
145+
}

0 commit comments

Comments
 (0)