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
6 changes: 6 additions & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,12 @@ impl Item {
self.stability.as_ref().map(|s| &s.since[..])
}

pub fn is_non_exhaustive(&self) -> bool {
self.attrs.other_attrs.iter()
.filter(|a| a.name().as_str() == "non_exhaustive")
.count() > 0
Copy link
Member

@frewsxcv frewsxcv Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be more peformant to use .any() instead of .count() > 0

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this.

}

/// 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
40 changes: 37 additions & 3 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2262,6 +2262,35 @@ 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, "<p class='non-exhaustive'>")?;

if item.is_struct() {
write!(w, "This struct is marked as non-exhaustive as additional fields may be \
added in the future. This means that this struct cannot be constructed in \
external crates using the traditional <code>Struct {{ .. }}</code> syntax;
cannot be matched against without a wildcard <code>..</code>; and \
functional-record-updates do not work on this struct.")?;
} else if item.is_enum() {
write!(w, "This enum is marked as non-exhaustive, and additional variants may be \
added in the future. When matching over values of this type, an extra \
<code>_</code> arm must be added to account for future extensions.")?;
} else {
write!(w, "This type will require a wildcard arm in any match statements or \
constructors.")?;
}

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

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 +3151,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 +3285,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 +3388,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
4 changes: 3 additions & 1 deletion src/librustdoc/html/static/themes/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ pre {
.content .fnname{ color: #2BAB63; }
.content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; }

.non-exhaustive { color: #DDD; margin-bottom: 1em; }

pre.rust .comment { color: #8d8d8b; }
pre.rust .doccomment { color: #8ca375; }

Expand Down Expand Up @@ -406,4 +408,4 @@ kbd {
}
.search-results td span.grey {
color: #ccc;
}
}
4 changes: 3 additions & 1 deletion src/librustdoc/html/static/themes/light.css
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ pre {
.content .fnname { color: #9a6e31; }
.content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; }

.non-exhaustive { color: #222; margin-bottom: 1em; }

pre.rust .comment { color: #8E908C; }
pre.rust .doccomment { color: #4D4D4C; }

Expand Down Expand Up @@ -400,4 +402,4 @@ kbd {
}
.search-results td span.grey {
color: #999;
}
}