Skip to content

Commit 6792bd9

Browse files
committed
Support unions in rustdoc
1 parent 641d8e9 commit 6792bd9

File tree

11 files changed

+204
-8
lines changed

11 files changed

+204
-8
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
8888
ret.extend(build_impls(cx, tcx, did));
8989
clean::StructItem(build_struct(cx, tcx, did))
9090
}
91+
Def::Union(did) => {
92+
record_extern_fqn(cx, did, clean::TypeUnion);
93+
ret.extend(build_impls(cx, tcx, did));
94+
clean::UnionItem(build_union(cx, tcx, did))
95+
}
9196
Def::TyAlias(did) => {
9297
record_extern_fqn(cx, did, clean::TypeTypedef);
9398
ret.extend(build_impls(cx, tcx, did));
@@ -214,6 +219,20 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
214219
}
215220
}
216221

222+
fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
223+
did: DefId) -> clean::Union {
224+
let t = tcx.lookup_item_type(did);
225+
let predicates = tcx.lookup_predicates(did);
226+
let variant = tcx.lookup_adt_def(did).struct_variant();
227+
228+
clean::Union {
229+
struct_type: doctree::Plain,
230+
generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
231+
fields: variant.fields.clean(cx),
232+
fields_stripped: false,
233+
}
234+
}
235+
217236
fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
218237
did: DefId) -> clean::ItemEnum {
219238
let t = tcx.lookup_item_type(did);

src/librustdoc/clean/mod.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ impl Item {
321321
pub fn has_stripped_fields(&self) -> Option<bool> {
322322
match self.inner {
323323
StructItem(ref _struct) => Some(_struct.fields_stripped),
324+
UnionItem(ref union) => Some(union.fields_stripped),
324325
VariantItem(Variant { kind: StructVariant(ref vstruct)} ) => {
325326
Some(vstruct.fields_stripped)
326327
},
@@ -351,6 +352,7 @@ pub enum ItemEnum {
351352
ExternCrateItem(String, Option<String>),
352353
ImportItem(Import),
353354
StructItem(Struct),
355+
UnionItem(Union),
354356
EnumItem(Enum),
355357
FunctionItem(Function),
356358
ModuleItem(Module),
@@ -414,6 +416,7 @@ impl Clean<Item> for doctree::Module {
414416
items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
415417
items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
416418
items.extend(self.structs.iter().map(|x| x.clean(cx)));
419+
items.extend(self.unions.iter().map(|x| x.clean(cx)));
417420
items.extend(self.enums.iter().map(|x| x.clean(cx)));
418421
items.extend(self.fns.iter().map(|x| x.clean(cx)));
419422
items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
@@ -1464,6 +1467,7 @@ pub enum TypeKind {
14641467
TypeConst,
14651468
TypeStatic,
14661469
TypeStruct,
1470+
TypeUnion,
14671471
TypeTrait,
14681472
TypeVariant,
14691473
TypeTypedef,
@@ -1801,12 +1805,13 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
18011805
decl: (cx.map.local_def_id(0), &fty.sig).clean(cx),
18021806
abi: fty.abi,
18031807
}),
1804-
ty::TyUnion(..) => unimplemented_unions!(),
18051808
ty::TyStruct(def, substs) |
1809+
ty::TyUnion(def, substs) |
18061810
ty::TyEnum(def, substs) => {
18071811
let did = def.did;
18081812
let kind = match self.sty {
18091813
ty::TyStruct(..) => TypeStruct,
1814+
ty::TyUnion(..) => TypeUnion,
18101815
_ => TypeEnum,
18111816
};
18121817
inline::record_extern_fqn(cx, did, kind);
@@ -1929,6 +1934,14 @@ pub struct Struct {
19291934
pub fields_stripped: bool,
19301935
}
19311936

1937+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1938+
pub struct Union {
1939+
pub struct_type: doctree::StructType,
1940+
pub generics: Generics,
1941+
pub fields: Vec<Item>,
1942+
pub fields_stripped: bool,
1943+
}
1944+
19321945
impl Clean<Item> for doctree::Struct {
19331946
fn clean(&self, cx: &DocContext) -> Item {
19341947
Item {
@@ -1949,6 +1962,26 @@ impl Clean<Item> for doctree::Struct {
19491962
}
19501963
}
19511964

1965+
impl Clean<Item> for doctree::Union {
1966+
fn clean(&self, cx: &DocContext) -> Item {
1967+
Item {
1968+
name: Some(self.name.clean(cx)),
1969+
attrs: self.attrs.clean(cx),
1970+
source: self.whence.clean(cx),
1971+
def_id: cx.map.local_def_id(self.id),
1972+
visibility: self.vis.clean(cx),
1973+
stability: self.stab.clean(cx),
1974+
deprecation: self.depr.clean(cx),
1975+
inner: UnionItem(Union {
1976+
struct_type: self.struct_type,
1977+
generics: self.generics.clean(cx),
1978+
fields: self.fields.clean(cx),
1979+
fields_stripped: false,
1980+
}),
1981+
}
1982+
}
1983+
}
1984+
19521985
/// This is a more limited form of the standard Struct, different in that
19531986
/// it lacks the things most items have (name, id, parameterization). Found
19541987
/// only as a variant in an enum.
@@ -2748,6 +2781,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
27482781
Def::Enum(i) => (i, TypeEnum),
27492782
Def::Trait(i) => (i, TypeTrait),
27502783
Def::Struct(i) => (i, TypeStruct),
2784+
Def::Union(i) => (i, TypeUnion),
27512785
Def::Mod(i) => (i, TypeModule),
27522786
Def::Static(i, _) => (i, TypeStatic),
27532787
Def::Variant(i, _) => (i, TypeEnum),

src/librustdoc/doctree.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub struct Module {
3030
pub extern_crates: Vec<ExternCrate>,
3131
pub imports: Vec<Import>,
3232
pub structs: Vec<Struct>,
33+
pub unions: Vec<Union>,
3334
pub enums: Vec<Enum>,
3435
pub fns: Vec<Function>,
3536
pub mods: Vec<Module>,
@@ -62,6 +63,7 @@ impl Module {
6263
extern_crates: Vec::new(),
6364
imports : Vec::new(),
6465
structs : Vec::new(),
66+
unions : Vec::new(),
6567
enums : Vec::new(),
6668
fns : Vec::new(),
6769
mods : Vec::new(),
@@ -108,6 +110,19 @@ pub struct Struct {
108110
pub whence: Span,
109111
}
110112

113+
pub struct Union {
114+
pub vis: hir::Visibility,
115+
pub stab: Option<attr::Stability>,
116+
pub depr: Option<attr::Deprecation>,
117+
pub id: NodeId,
118+
pub struct_type: StructType,
119+
pub name: Name,
120+
pub generics: hir::Generics,
121+
pub attrs: hir::HirVec<ast::Attribute>,
122+
pub fields: hir::HirVec<hir::StructField>,
123+
pub whence: Span,
124+
}
125+
111126
pub struct Enum {
112127
pub vis: hir::Visibility,
113128
pub stab: Option<attr::Stability>,

src/librustdoc/fold.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ pub trait DocFolder : Sized {
4949
i.fields.iter().any(|f| f.is_stripped());
5050
StructItem(i)
5151
},
52+
UnionItem(mut i) => {
53+
let num_fields = i.fields.len();
54+
i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
55+
i.fields_stripped |= num_fields != i.fields.len() ||
56+
i.fields.iter().any(|f| f.is_stripped());
57+
UnionItem(i)
58+
},
5259
EnumItem(mut i) => {
5360
let num_variants = i.variants.len();
5461
i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();

src/librustdoc/html/item_type.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub enum ItemType {
4040
AssociatedType = 16,
4141
Constant = 17,
4242
AssociatedConst = 18,
43+
Union = 19,
4344
}
4445

4546

@@ -62,6 +63,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
6263
clean::ExternCrateItem(..) => ItemType::ExternCrate,
6364
clean::ImportItem(..) => ItemType::Import,
6465
clean::StructItem(..) => ItemType::Struct,
66+
clean::UnionItem(..) => ItemType::Union,
6567
clean::EnumItem(..) => ItemType::Enum,
6668
clean::FunctionItem(..) => ItemType::Function,
6769
clean::TypedefItem(..) => ItemType::Typedef,
@@ -89,6 +91,7 @@ impl From<clean::TypeKind> for ItemType {
8991
fn from(kind: clean::TypeKind) -> ItemType {
9092
match kind {
9193
clean::TypeStruct => ItemType::Struct,
94+
clean::TypeUnion => ItemType::Union,
9295
clean::TypeEnum => ItemType::Enum,
9396
clean::TypeFunction => ItemType::Function,
9497
clean::TypeTrait => ItemType::Trait,
@@ -108,6 +111,7 @@ impl ItemType {
108111
ItemType::ExternCrate => "externcrate",
109112
ItemType::Import => "import",
110113
ItemType::Struct => "struct",
114+
ItemType::Union => "union",
111115
ItemType::Enum => "enum",
112116
ItemType::Function => "fn",
113117
ItemType::Typedef => "type",

src/librustdoc/html/render.rs

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,7 @@ impl DocFolder for Cache {
10531053
// information if present.
10541054
Some(&(ref fqp, ItemType::Trait)) |
10551055
Some(&(ref fqp, ItemType::Struct)) |
1056+
Some(&(ref fqp, ItemType::Union)) |
10561057
Some(&(ref fqp, ItemType::Enum)) =>
10571058
Some(&fqp[..fqp.len() - 1]),
10581059
Some(..) => Some(&*self.stack),
@@ -1106,7 +1107,8 @@ impl DocFolder for Cache {
11061107
clean::TypedefItem(..) | clean::TraitItem(..) |
11071108
clean::FunctionItem(..) | clean::ModuleItem(..) |
11081109
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
1109-
clean::ConstantItem(..) | clean::StaticItem(..)
1110+
clean::ConstantItem(..) | clean::StaticItem(..) |
1111+
clean::UnionItem(..)
11101112
if !self.stripped_mod => {
11111113
// Reexported items mean that the same id can show up twice
11121114
// in the rustdoc ast that we're looking at. We know,
@@ -1141,7 +1143,8 @@ impl DocFolder for Cache {
11411143
// Maintain the parent stack
11421144
let orig_parent_is_trait_impl = self.parent_is_trait_impl;
11431145
let parent_pushed = match item.inner {
1144-
clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
1146+
clean::TraitItem(..) | clean::EnumItem(..) |
1147+
clean::StructItem(..) | clean::UnionItem(..) => {
11451148
self.parent_stack.push(item.def_id);
11461149
self.parent_is_trait_impl = false;
11471150
true
@@ -1557,6 +1560,7 @@ impl<'a> fmt::Display for Item<'a> {
15571560
clean::FunctionItem(..) => write!(fmt, "Function ")?,
15581561
clean::TraitItem(..) => write!(fmt, "Trait ")?,
15591562
clean::StructItem(..) => write!(fmt, "Struct ")?,
1563+
clean::UnionItem(..) => write!(fmt, "Union ")?,
15601564
clean::EnumItem(..) => write!(fmt, "Enum ")?,
15611565
clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
15621566
_ => {}
@@ -1613,6 +1617,7 @@ impl<'a> fmt::Display for Item<'a> {
16131617
item_function(fmt, self.cx, self.item, f),
16141618
clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
16151619
clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s),
1620+
clean::UnionItem(ref s) => item_union(fmt, self.cx, self.item, s),
16161621
clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e),
16171622
clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t),
16181623
clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m),
@@ -1715,7 +1720,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
17151720
ItemType::Trait => 9,
17161721
ItemType::Function => 10,
17171722
ItemType::Typedef => 12,
1718-
_ => 13 + ty as u8,
1723+
ItemType::Union => 13,
1724+
_ => 14 + ty as u8,
17191725
}
17201726
}
17211727

@@ -1759,6 +1765,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
17591765
ItemType::Import => ("reexports", "Reexports"),
17601766
ItemType::Module => ("modules", "Modules"),
17611767
ItemType::Struct => ("structs", "Structs"),
1768+
ItemType::Union => ("unions", "Unions"),
17621769
ItemType::Enum => ("enums", "Enums"),
17631770
ItemType::Function => ("functions", "Functions"),
17641771
ItemType::Typedef => ("types", "Type Definitions"),
@@ -2312,6 +2319,40 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
23122319
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
23132320
}
23142321

2322+
fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
2323+
s: &clean::Union) -> fmt::Result {
2324+
write!(w, "<pre class='rust union'>")?;
2325+
render_attributes(w, it)?;
2326+
render_union(w,
2327+
it,
2328+
Some(&s.generics),
2329+
&s.fields,
2330+
"",
2331+
true)?;
2332+
write!(w, "</pre>")?;
2333+
2334+
document(w, cx, it)?;
2335+
let mut fields = s.fields.iter().filter_map(|f| {
2336+
match f.inner {
2337+
clean::StructFieldItem(ref ty) => Some((f, ty)),
2338+
_ => None,
2339+
}
2340+
}).peekable();
2341+
if fields.peek().is_some() {
2342+
write!(w, "<h2 class='fields'>Fields</h2>")?;
2343+
for (field, ty) in fields {
2344+
write!(w, "<span id='{shortty}.{name}' class='{shortty}'><code>{name}: {ty}</code>
2345+
</span><span class='stab {stab}'></span>",
2346+
shortty = ItemType::StructField,
2347+
stab = field.stability_class(),
2348+
name = field.name.as_ref().unwrap(),
2349+
ty = ty)?;
2350+
document(w, cx, field)?;
2351+
}
2352+
}
2353+
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
2354+
}
2355+
23152356
fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
23162357
e: &clean::Enum) -> fmt::Result {
23172358
write!(w, "<pre class='rust enum'>")?;
@@ -2514,6 +2555,40 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
25142555
Ok(())
25152556
}
25162557

2558+
fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
2559+
g: Option<&clean::Generics>,
2560+
fields: &[clean::Item],
2561+
tab: &str,
2562+
structhead: bool) -> fmt::Result {
2563+
write!(w, "{}{}{}",
2564+
VisSpace(&it.visibility),
2565+
if structhead {"union "} else {""},
2566+
it.name.as_ref().unwrap())?;
2567+
if let Some(g) = g {
2568+
write!(w, "{}", g)?
2569+
}
2570+
if let Some(g) = g {
2571+
write!(w, "{}", WhereClause(g))?
2572+
}
2573+
2574+
write!(w, " {{\n{}", tab)?;
2575+
for field in fields {
2576+
if let clean::StructFieldItem(ref ty) = field.inner {
2577+
write!(w, " {}{}: {},\n{}",
2578+
VisSpace(&field.visibility),
2579+
field.name.as_ref().unwrap(),
2580+
*ty,
2581+
tab)?;
2582+
}
2583+
}
2584+
2585+
if it.has_stripped_fields().unwrap() {
2586+
write!(w, " // some fields omitted\n{}", tab)?;
2587+
}
2588+
write!(w, "}}")?;
2589+
Ok(())
2590+
}
2591+
25172592
#[derive(Copy, Clone)]
25182593
enum AssocItemLink<'a> {
25192594
Anchor(Option<&'a str>),

src/librustdoc/html/static/main.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"primitive",
3535
"associatedtype",
3636
"constant",
37-
"associatedconstant"];
37+
"associatedconstant",
38+
"union"];
3839

3940
// used for special search precedence
4041
var TY_PRIMITIVE = itemTypes.indexOf("primitive");

src/librustdoc/passes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
113113
clean::TraitItem(..) | clean::FunctionItem(..) |
114114
clean::VariantItem(..) | clean::MethodItem(..) |
115115
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
116-
clean::ConstantItem(..) => {
116+
clean::ConstantItem(..) | clean::UnionItem(..) => {
117117
if i.def_id.is_local() {
118118
if !self.access_levels.is_exported(i.def_id) {
119119
return None;

0 commit comments

Comments
 (0)