Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC 2008 non-exhaustive enums/structs: Rustdoc #51854

Merged
merged 8 commits into from
Jul 19, 2018
5 changes: 5 additions & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,11 @@ impl Item {
self.stability.as_ref().map(|s| &s.since[..])
}

pub fn is_non_exhaustive(&self) -> bool {
self.attrs.other_attrs.iter()
.any(|a| a.name().as_str() == "non_exhaustive")
}

/// Returns a documentation-level item type from the item.
pub fn type_(&self) -> ItemType {
ItemType::from(self)
Expand Down
11 changes: 10 additions & 1 deletion src/librustdoc/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,16 @@ pub trait DocFolder : Sized {

/// don't override!
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item;
let Item {
attrs,
name,
source,
visibility,
def_id,
inner,
stability,
deprecation,
} = item;

let inner = match inner {
StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
Expand Down
42 changes: 39 additions & 3 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2262,6 +2262,37 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item)
Ok(())
}

fn document_non_exhaustive_header(item: &clean::Item) -> &str {
if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" }
}

fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
if item.is_non_exhaustive() {
write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" }
})?;

if item.is_struct() {
write!(w, "Non-exhaustive structs could have additional fields added in future. \
Therefore, non-exhaustive structs cannot be constructed in external crates \
using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \
matched against without a wildcard <code>..</code>; and \
struct update syntax will not work.")?;
} else if item.is_enum() {
write!(w, "Non-exhaustive enums could have additional variants added in future. \
Therefore, when matching against variants of non-exhaustive enums, an \
extra wildcard arm must be added to account for any future variants.")?;
} else {
write!(w, "This type will require a wildcard arm in any match statements or \
constructors.")?;
}

write!(w, "</div>")?;
}

Ok(())
}

fn name_key(name: &str) -> (&str, u64, usize) {
// find number at end
let split = name.bytes().rposition(|b| b < b'0' || b'9' < b).map_or(0, |s| s + 1);
Expand Down Expand Up @@ -3122,7 +3153,9 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
if let doctree::Plain = s.struct_type {
if fields.peek().is_some() {
write!(w, "<h2 id='fields' class='fields small-section-header'>
Fields<a href='#fields' class='anchor'></a></h2>")?;
Fields{}<a href='#fields' class='anchor'></a></h2>",
document_non_exhaustive_header(it))?;
document_non_exhaustive(w, it)?;
for (field, ty) in fields {
let id = derive_id(format!("{}.{}",
ItemType::StructField,
Expand Down Expand Up @@ -3254,7 +3287,9 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
document(w, cx, it)?;
if !e.variants.is_empty() {
write!(w, "<h2 id='variants' class='variants small-section-header'>
Variants<a href='#variants' class='anchor'></a></h2>\n")?;
Variants{}<a href='#variants' class='anchor'></a></h2>\n",
document_non_exhaustive_header(it))?;
document_non_exhaustive(w, it)?;
for variant in &e.variants {
let id = derive_id(format!("{}.{}",
ItemType::Variant,
Expand Down Expand Up @@ -3355,7 +3390,8 @@ const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[
"must_use",
"no_mangle",
"repr",
"unsafe_destructor_blind_to_params"
"unsafe_destructor_blind_to_params",
"non_exhaustive"
];

fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
Expand Down
23 changes: 20 additions & 3 deletions src/librustdoc/html/static/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1993,15 +1993,18 @@
onEach(e.getElementsByClassName('associatedconstant'), func);
});

function createToggle(otherMessage, extraClass) {
function createToggle(otherMessage, fontSize, extraClass) {
var span = document.createElement('span');
span.className = 'toggle-label';
span.style.display = 'none';
if (!otherMessage) {
span.innerHTML = '&nbsp;Expand&nbsp;description';
} else {
span.innerHTML = otherMessage;
span.style.fontSize = '20px';
}

if (fontSize) {
span.style.fontSize = fontSize;
}

var mainToggle = toggle.cloneNode(true);
Expand Down Expand Up @@ -2040,13 +2043,27 @@
}
if (e.parentNode.id === "main") {
var otherMessage;
var fontSize;
var extraClass;

if (hasClass(e, "type-decl")) {
fontSize = "20px";
otherMessage = '&nbsp;Show&nbsp;declaration';
} else if (hasClass(e, "non-exhaustive")) {
otherMessage = '&nbsp;This&nbsp;';
if (hasClass(e, "non-exhaustive-struct")) {
otherMessage += 'struct';
} else if (hasClass(e, "non-exhaustive-enum")) {
otherMessage += 'enum';
} else if (hasClass(e, "non-exhaustive-type")) {
otherMessage += 'type';
}
otherMessage += '&nbsp;is&nbsp;marked&nbsp;as&nbsp;non-exhaustive';
} else if (hasClass(e.childNodes[0], "impl-items")) {
extraClass = "marg-left";
}
e.parentNode.insertBefore(createToggle(otherMessage, extraClass), e);

e.parentNode.insertBefore(createToggle(otherMessage, fontSize, extraClass), e);
if (otherMessage && getCurrentValue('rustdoc-item-declarations') !== "false") {
collapseDocs(e.previousSibling.childNodes[0], "toggle");
}
Expand Down
6 changes: 5 additions & 1 deletion src/librustdoc/html/static/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -1358,4 +1358,8 @@ kbd {
}
#all-types > p {
margin: 5px 0;
}
}

.non-exhaustive {
margin-bottom: 1em;
}
2 changes: 1 addition & 1 deletion src/librustdoc/html/static/themes/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -406,4 +406,4 @@ kbd {
}
.search-results td span.grey {
color: #ccc;
}
}
2 changes: 1 addition & 1 deletion src/librustdoc/html/static/themes/light.css
Original file line number Diff line number Diff line change
Expand Up @@ -400,4 +400,4 @@ kbd {
}
.search-results td span.grey {
color: #999;
}
}