Skip to content

Commit 11864c4

Browse files
committed
Auto merge of #51854 - davidtwco:rfc-2008-rustdoc, r=QuietMisdreavus
RFC 2008 non-exhaustive enums/structs: Rustdoc Part of #44109. Not sure how those who maintain rustdoc primarily would prefer this addition look or where it should be placed, happy to make any changes required. r? @QuietMisdreavus (not sure if this is the right person, just guessing)
2 parents a8247dd + b671bdc commit 11864c4

File tree

7 files changed

+81
-10
lines changed

7 files changed

+81
-10
lines changed

src/librustdoc/clean/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,11 @@ impl Item {
496496
self.stability.as_ref().map(|s| &s.since[..])
497497
}
498498

499+
pub fn is_non_exhaustive(&self) -> bool {
500+
self.attrs.other_attrs.iter()
501+
.any(|a| a.name().as_str() == "non_exhaustive")
502+
}
503+
499504
/// Returns a documentation-level item type from the item.
500505
pub fn type_(&self) -> ItemType {
501506
ItemType::from(self)

src/librustdoc/fold.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,16 @@ pub trait DocFolder : Sized {
9292

9393
/// don't override!
9494
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
95-
let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item;
95+
let Item {
96+
attrs,
97+
name,
98+
source,
99+
visibility,
100+
def_id,
101+
inner,
102+
stability,
103+
deprecation,
104+
} = item;
96105

97106
let inner = match inner {
98107
StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),

src/librustdoc/html/render.rs

+39-3
Original file line numberDiff line numberDiff line change
@@ -2276,6 +2276,37 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item)
22762276
Ok(())
22772277
}
22782278

2279+
fn document_non_exhaustive_header(item: &clean::Item) -> &str {
2280+
if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" }
2281+
}
2282+
2283+
fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
2284+
if item.is_non_exhaustive() {
2285+
write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
2286+
if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" }
2287+
})?;
2288+
2289+
if item.is_struct() {
2290+
write!(w, "Non-exhaustive structs could have additional fields added in future. \
2291+
Therefore, non-exhaustive structs cannot be constructed in external crates \
2292+
using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \
2293+
matched against without a wildcard <code>..</code>; and \
2294+
struct update syntax will not work.")?;
2295+
} else if item.is_enum() {
2296+
write!(w, "Non-exhaustive enums could have additional variants added in future. \
2297+
Therefore, when matching against variants of non-exhaustive enums, an \
2298+
extra wildcard arm must be added to account for any future variants.")?;
2299+
} else {
2300+
write!(w, "This type will require a wildcard arm in any match statements or \
2301+
constructors.")?;
2302+
}
2303+
2304+
write!(w, "</div>")?;
2305+
}
2306+
2307+
Ok(())
2308+
}
2309+
22792310
fn name_key(name: &str) -> (&str, u64, usize) {
22802311
// find number at end
22812312
let split = name.bytes().rposition(|b| b < b'0' || b'9' < b).map_or(0, |s| s + 1);
@@ -3136,7 +3167,9 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
31363167
if let doctree::Plain = s.struct_type {
31373168
if fields.peek().is_some() {
31383169
write!(w, "<h2 id='fields' class='fields small-section-header'>
3139-
Fields<a href='#fields' class='anchor'></a></h2>")?;
3170+
Fields{}<a href='#fields' class='anchor'></a></h2>",
3171+
document_non_exhaustive_header(it))?;
3172+
document_non_exhaustive(w, it)?;
31403173
for (field, ty) in fields {
31413174
let id = derive_id(format!("{}.{}",
31423175
ItemType::StructField,
@@ -3268,7 +3301,9 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
32683301
document(w, cx, it)?;
32693302
if !e.variants.is_empty() {
32703303
write!(w, "<h2 id='variants' class='variants small-section-header'>
3271-
Variants<a href='#variants' class='anchor'></a></h2>\n")?;
3304+
Variants{}<a href='#variants' class='anchor'></a></h2>\n",
3305+
document_non_exhaustive_header(it))?;
3306+
document_non_exhaustive(w, it)?;
32723307
for variant in &e.variants {
32733308
let id = derive_id(format!("{}.{}",
32743309
ItemType::Variant,
@@ -3369,7 +3404,8 @@ const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[
33693404
"must_use",
33703405
"no_mangle",
33713406
"repr",
3372-
"unsafe_destructor_blind_to_params"
3407+
"unsafe_destructor_blind_to_params",
3408+
"non_exhaustive"
33733409
];
33743410

33753411
fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {

src/librustdoc/html/static/main.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -2001,15 +2001,18 @@
20012001
onEach(e.getElementsByClassName('associatedconstant'), func);
20022002
});
20032003

2004-
function createToggle(otherMessage, extraClass) {
2004+
function createToggle(otherMessage, fontSize, extraClass) {
20052005
var span = document.createElement('span');
20062006
span.className = 'toggle-label';
20072007
span.style.display = 'none';
20082008
if (!otherMessage) {
20092009
span.innerHTML = '&nbsp;Expand&nbsp;description';
20102010
} else {
20112011
span.innerHTML = otherMessage;
2012-
span.style.fontSize = '20px';
2012+
}
2013+
2014+
if (fontSize) {
2015+
span.style.fontSize = fontSize;
20132016
}
20142017

20152018
var mainToggle = toggle.cloneNode(true);
@@ -2048,13 +2051,27 @@
20482051
}
20492052
if (e.parentNode.id === "main") {
20502053
var otherMessage;
2054+
var fontSize;
20512055
var extraClass;
2056+
20522057
if (hasClass(e, "type-decl")) {
2058+
fontSize = "20px";
20532059
otherMessage = '&nbsp;Show&nbsp;declaration';
2060+
} else if (hasClass(e, "non-exhaustive")) {
2061+
otherMessage = '&nbsp;This&nbsp;';
2062+
if (hasClass(e, "non-exhaustive-struct")) {
2063+
otherMessage += 'struct';
2064+
} else if (hasClass(e, "non-exhaustive-enum")) {
2065+
otherMessage += 'enum';
2066+
} else if (hasClass(e, "non-exhaustive-type")) {
2067+
otherMessage += 'type';
2068+
}
2069+
otherMessage += '&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive';
20542070
} else if (hasClass(e.childNodes[0], "impl-items")) {
20552071
extraClass = "marg-left";
20562072
}
2057-
e.parentNode.insertBefore(createToggle(otherMessage, extraClass), e);
2073+
2074+
e.parentNode.insertBefore(createToggle(otherMessage, fontSize, extraClass), e);
20582075
if (otherMessage && getCurrentValue('rustdoc-item-declarations') !== "false") {
20592076
collapseDocs(e.previousSibling.childNodes[0], "toggle");
20602077
}

src/librustdoc/html/static/rustdoc.css

+5-1
Original file line numberDiff line numberDiff line change
@@ -1358,4 +1358,8 @@ kbd {
13581358
}
13591359
#all-types > p {
13601360
margin: 5px 0;
1361-
}
1361+
}
1362+
1363+
.non-exhaustive {
1364+
margin-bottom: 1em;
1365+
}

src/librustdoc/html/static/themes/dark.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -406,4 +406,4 @@ kbd {
406406
}
407407
.search-results td span.grey {
408408
color: #ccc;
409-
}
409+
}

src/librustdoc/html/static/themes/light.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -400,4 +400,4 @@ kbd {
400400
}
401401
.search-results td span.grey {
402402
color: #999;
403-
}
403+
}

0 commit comments

Comments
 (0)