Skip to content

Commit a0e19fd

Browse files
committed
WIP implement a machine readable print-type-info API
1 parent 6c5212f commit a0e19fd

File tree

4 files changed

+365
-180
lines changed

4 files changed

+365
-180
lines changed

src/librustc/session/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
12-
pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
11+
pub use self::print_type_info::{CodeStats};
12+
// pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
13+
// pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
1314

1415
use dep_graph::DepGraph;
1516
use hir::def_id::{CrateNum, DefIndex};
@@ -51,7 +52,8 @@ use std::rc::Rc;
5152
use std::sync::{Once, ONCE_INIT};
5253
use std::time::Duration;
5354

54-
mod code_stats;
55+
// mod code_stats;
56+
pub mod print_type_info;
5557
pub mod config;
5658
pub mod filesearch;
5759
pub mod search_paths;
+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
use rustc_data_structures::fx::FxHashSet;
13+
use std::mem;
14+
use std::hash::{Hash, Hasher};
15+
use std::collections::BTreeMap;
16+
use rustc_serialize::json::Json;
17+
18+
pub struct CodeStats {
19+
types: FxHashSet<Type>,
20+
}
21+
22+
/// A Type name, with certain modifiers applied.
23+
///
24+
/// While a Type can have a name like rust::u32, a ComplexTypeName
25+
/// can include nested pointer/array modifiers:
26+
///
27+
/// * `*const ComplexTypeName`
28+
/// * `[ComplexTypeName; N]`
29+
///
30+
/// This avoids metadata blowup.
31+
///
32+
/// For example: `*const [*mut [rust::u32, 12], 32]`
33+
pub type ComplexTypeName = String;
34+
35+
pub struct Type {
36+
pub name: String,
37+
pub size: u64,
38+
pub align: u64,
39+
pub public: bool,
40+
pub kind: TypeKind,
41+
}
42+
43+
pub enum TypeKind {
44+
PrimitiveInt,
45+
PrimitiveFloat,
46+
Opaque,
47+
Struct { fields: Vec<Field> },
48+
Union { fields: Vec<Field> },
49+
Enum { base_type: ComplexTypeName, cases: Vec<Case> },
50+
}
51+
52+
pub struct Field {
53+
pub name: String,
54+
pub type_name: ComplexTypeName,
55+
pub offset: u64,
56+
pub public: bool,
57+
}
58+
59+
pub struct Case {
60+
pub name: String,
61+
pub value: i64, // TODO: u64/u128/i128? (serialize doesn't support)
62+
}
63+
64+
impl PartialEq for Type {
65+
fn eq(&self, other: &Self) -> bool { self.name == other.name }
66+
}
67+
impl Eq for Type {}
68+
impl Hash for Type {
69+
fn hash<H: Hasher>(&self, state: &mut H) {
70+
self.name.hash(state);
71+
}
72+
}
73+
74+
75+
impl TypeKind {
76+
fn as_str(&self) -> &'static str {
77+
match *self {
78+
TypeKind::PrimitiveInt => "primitive_int",
79+
TypeKind::PrimitiveFloat => "primitive_float",
80+
TypeKind::Opaque => "opaque",
81+
TypeKind::Struct { .. } => "struct",
82+
TypeKind::Union { .. } => "union",
83+
TypeKind::Enum { .. } => "enum",
84+
}
85+
}
86+
}
87+
88+
impl CodeStats {
89+
pub fn new() -> Self {
90+
CodeStats { types: FxHashSet::default() }
91+
}
92+
93+
pub fn insert(&mut self, ty: Type) {
94+
self.types.insert(ty);
95+
}
96+
97+
pub fn print_type_sizes(&mut self) {
98+
let types = mem::replace(&mut self.types, FxHashSet::default());
99+
100+
let mut output = Vec::with_capacity(types.len());
101+
102+
for ty in types {
103+
let mut json = BTreeMap::new();
104+
105+
json.insert("name".to_string(), Json::String(ty.name));
106+
json.insert("size".to_string(), Json::U64(ty.size));
107+
json.insert("align".to_string(), Json::U64(ty.align));
108+
json.insert("public".to_string(), Json::Boolean(ty.public));
109+
json.insert("kind".to_string(), Json::String(ty.kind.as_str().to_string()));
110+
111+
match ty.kind {
112+
TypeKind::Struct { fields } | TypeKind::Union { fields } => {
113+
let fields_json = fields.into_iter().map(field_to_json).collect();
114+
json.insert("fields".to_string(), Json::Array(fields_json));
115+
}
116+
TypeKind::Enum { base_type, cases } => {
117+
json.insert("base_type".to_string(), Json::String(base_type));
118+
let cases_json = cases.into_iter().map(case_to_json).collect();
119+
json.insert("cases".to_string(), Json::Array(cases_json));
120+
}
121+
_ => { /* nothing */ }
122+
}
123+
124+
output.push(Json::Object(json));
125+
}
126+
127+
println!("WARNING: these values are platform-specific, implementation-specific, \
128+
and compilation-specific. They can and will change for absolutely no reason. \
129+
To use this properly, you must recompute and evaluate them on each compilation \
130+
of your crate. Yes we broke your JSON parsing just to say this. We're not \
131+
kidding here.");
132+
println!("{}", Json::Array(output));
133+
}
134+
}
135+
136+
fn case_to_json(case: Case) -> Json {
137+
let mut json = BTreeMap::new();
138+
139+
json.insert("name".to_string(), Json::String(case.name));
140+
json.insert("value".to_string(), Json::I64(case.value));
141+
142+
Json::Object(json)
143+
}
144+
145+
fn field_to_json(field: Field) -> Json {
146+
let mut json = BTreeMap::new();
147+
148+
json.insert("name".to_string(), Json::String(field.name));
149+
json.insert("type".to_string(), Json::String(field.type_name));
150+
json.insert("offset".to_string(), Json::U64(field.offset));
151+
json.insert("public".to_string(), Json::Boolean(field.public));
152+
153+
Json::Object(json)
154+
}

0 commit comments

Comments
 (0)