diff options
| author | bors <bors@rust-lang.org> | 2017-11-21 03:03:28 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-11-21 03:03:28 +0000 |
| commit | 421a2113a840aa5801230e7226fc9628100072ef (patch) | |
| tree | 17e45188fe0fcdd5ffcb838a33a200562528ab67 | |
| parent | 1e44fee88d48e9f7844c6d316ae8540db19dc9fa (diff) | |
| parent | 6047a0365976cbf7ad2991e6d88e4adf2fc6d0f4 (diff) | |
| download | rust-421a2113a840aa5801230e7226fc9628100072ef.tar.gz rust-421a2113a840aa5801230e7226fc9628100072ef.zip | |
Auto merge of #45039 - QuietMisdreavus:doc-spotlight, r=GuillaumeGomez,QuietMisdreavus
show in docs whether the return type of a function impls Iterator/Read/Write
Closes #25928
This PR makes it so that when rustdoc documents a function, it checks the return type to see whether it implements a handful of specific traits. If so, it will print the impl and any associated types. Rather than doing this via a whitelist within rustdoc, i chose to do this by a new `#[doc]` attribute parameter, so things like `Future` could tap into this if desired.
### Known shortcomings
~~The printing of impls currently uses the `where` class over the whole thing to shrink the font size relative to the function definition itself. Naturally, when the impl has a where clause of its own, it gets shrunken even further:~~ (This is no longer a problem because the design changed and rendered this concern moot.)
The lookup currently just looks at the top-level type, not looking inside things like Result or Option, which renders the spotlights on Read/Write a little less useful:
<details><summary>`File::{open, create}` don't have spotlight info (pic of old design)</summary>

</details>
All three of the initially spotlighted traits are generically implemented on `&mut` references. Rustdoc currently treats a `&mut T` reference-to-a-generic as an impl on the reference primitive itself. `&mut Self` counts as a generic in the eyes of rustdoc. All this combines to create this lovely scene on `Iterator::by_ref`:
<details><summary>`Iterator::by_ref` spotlights Iterator, Read, and Write (pic of old design)</summary>

</details>
| -rw-r--r-- | src/doc/unstable-book/src/language-features/doc-spotlight.md | 30 | ||||
| -rw-r--r-- | src/libcore/iter/iterator.rs | 1 | ||||
| -rw-r--r-- | src/libcore/lib.rs | 18 | ||||
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 21 | ||||
| -rw-r--r-- | src/librustdoc/html/render.rs | 81 | ||||
| -rw-r--r-- | src/librustdoc/html/static/main.js | 28 | ||||
| -rw-r--r-- | src/librustdoc/html/static/rustdoc.css | 109 | ||||
| -rw-r--r-- | src/libstd/io/mod.rs | 2 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 6 | ||||
| -rw-r--r-- | src/test/compile-fail/feature-gate-doc_spotlight.rs | 14 | ||||
| -rw-r--r-- | src/test/rustdoc/doc-spotlight.rs | 46 |
13 files changed, 345 insertions, 14 deletions
diff --git a/src/doc/unstable-book/src/language-features/doc-spotlight.md b/src/doc/unstable-book/src/language-features/doc-spotlight.md new file mode 100644 index 00000000000..8117755fef1 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/doc-spotlight.md @@ -0,0 +1,30 @@ +# `doc_spotlight` + +The tracking issue for this feature is: [#45040] + +The `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute, +to "spotlight" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]` +attribute to a trait definition will make rustdoc print extra information for functions which return +a type that implements that trait. This attribute is applied to the `Iterator`, `io::Read`, and +`io::Write` traits in the standard library. + +You can do this on your own traits, like this: + +``` +#![feature(doc_spotlight)] + +#[doc(spotlight)] +pub trait MyTrait {} + +pub struct MyStruct; +impl MyTrait for MyStruct {} + +/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`, +/// without having to write that yourself! +pub fn my_fn() -> MyStruct { MyStruct } +``` + +This feature was originally implemented in PR [#45039]. + +[#45040]: https://github.com/rust-lang/rust/issues/45040 +[#45039]: https://github.com/rust-lang/rust/pull/45039 diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 40298389c1a..7f6d627536d 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -30,6 +30,7 @@ fn _assert_is_object_safe(_: &Iterator<Item=()>) {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \ `.iter()` or a similar method"] +#[doc(spotlight)] pub trait Iterator { /// The type of the elements being iterated over. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4a57417e86a..631b9f98589 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -107,6 +107,24 @@ #![feature(const_unsafe_cell_new)] #![feature(const_cell_new)] #![feature(const_nonzero_new)] +#![cfg_attr(not(stage0), feature(doc_spotlight))] + +#![cfg_attr(not(stage0), feature(const_min_value))] +#![cfg_attr(not(stage0), feature(const_max_value))] +#![cfg_attr(not(stage0), feature(const_atomic_bool_new))] +#![cfg_attr(not(stage0), feature(const_atomic_isize_new))] +#![cfg_attr(not(stage0), feature(const_atomic_usize_new))] +#![cfg_attr(not(stage0), feature(const_atomic_i8_new))] +#![cfg_attr(not(stage0), feature(const_atomic_u8_new))] +#![cfg_attr(not(stage0), feature(const_atomic_i16_new))] +#![cfg_attr(not(stage0), feature(const_atomic_u16_new))] +#![cfg_attr(not(stage0), feature(const_atomic_i32_new))] +#![cfg_attr(not(stage0), feature(const_atomic_u32_new))] +#![cfg_attr(not(stage0), feature(const_atomic_i64_new))] +#![cfg_attr(not(stage0), feature(const_atomic_u64_new))] +#![cfg_attr(not(stage0), feature(const_unsafe_cell_new))] +#![cfg_attr(not(stage0), feature(const_cell_new))] +#![cfg_attr(not(stage0), feature(const_nonzero_new))] #[prelude_import] #[allow(unused)] diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4c518167e08..820c3e856db 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -145,11 +145,13 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); + let is_spotlight = load_attrs(cx, did).has_doc_flag("spotlight"); clean::Trait { unsafety: cx.tcx.trait_def(did).unsafety, generics, items: trait_items, bounds: supertrait_bounds, + is_spotlight, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1d107c169b0..69226239c96 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -151,7 +151,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> { match module.inner { ModuleItem(ref module) => { for it in &module.items { - if it.is_extern_crate() && it.attrs.has_doc_masked() { + if it.is_extern_crate() && it.attrs.has_doc_flag("masked") { masked_crates.insert(it.def_id.krate); } } @@ -596,12 +596,12 @@ impl Attributes { None } - pub fn has_doc_masked(&self) -> bool { + pub fn has_doc_flag(&self, flag: &str) -> bool { for attr in &self.other_attrs { if !attr.check_name("doc") { continue; } if let Some(items) = attr.meta_item_list() { - if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name("masked")) { + if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) { return true; } } @@ -1331,19 +1331,31 @@ impl Clean<FunctionRetTy> for hir::FunctionRetTy { } } +impl GetDefId for FunctionRetTy { + fn def_id(&self) -> Option<DefId> { + match *self { + Return(ref ty) => ty.def_id(), + DefaultReturn => None, + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Trait { pub unsafety: hir::Unsafety, pub items: Vec<Item>, pub generics: Generics, pub bounds: Vec<TyParamBound>, + pub is_spotlight: bool, } impl Clean<Item> for doctree::Trait { fn clean(&self, cx: &DocContext) -> Item { + let attrs = self.attrs.clean(cx); + let is_spotlight = attrs.has_doc_flag("spotlight"); Item { name: Some(self.name.clean(cx)), - attrs: self.attrs.clean(cx), + attrs: attrs, source: self.whence.clean(cx), def_id: cx.tcx.hir.local_def_id(self.id), visibility: self.vis.clean(cx), @@ -1354,6 +1366,7 @@ impl Clean<Item> for doctree::Trait { items: self.items.clean(cx), generics: self.generics.clean(cx), bounds: self.bounds.clean(cx), + is_spotlight: is_spotlight, }), } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index e79a63fb8d8..8370f805828 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2268,7 +2268,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, AbiSpace(f.abi), it.name.as_ref().unwrap(), f.generics).len(); - write!(w, "<pre class='rust fn'>")?; + write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?; render_attributes(w, it)?; write!(w, "{vis}{constness}{unsafety}{abi}fn \ {name}{generics}{decl}{where_clause}</pre>", @@ -2402,8 +2402,9 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, let item_type = m.type_(); let id = derive_id(format!("{}.{}", item_type, name)); let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); - write!(w, "<h3 id='{id}' class='method'>\ + write!(w, "{extra}<h3 id='{id}' class='method'>\ <span id='{ns_id}' class='invisible'><code>", + extra = render_spotlight_traits(m)?, id = id, ns_id = ns_id)?; render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?; @@ -2605,10 +2606,10 @@ fn assoc_const(w: &mut fmt::Formatter, Ok(()) } -fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item, - bounds: &Vec<clean::TyParamBound>, - default: Option<&clean::Type>, - link: AssocItemLink) -> fmt::Result { +fn assoc_type<W: fmt::Write>(w: &mut W, it: &clean::Item, + bounds: &Vec<clean::TyParamBound>, + default: Option<&clean::Type>, + link: AssocItemLink) -> fmt::Result { write!(w, "type <a href='{}' class=\"type\">{}</a>", naive_assoc_href(it, link), it.name.as_ref().unwrap())?; @@ -3239,6 +3240,69 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { } } +fn render_spotlight_traits(item: &clean::Item) -> Result<String, fmt::Error> { + let mut out = String::new(); + + match item.inner { + clean::FunctionItem(clean::Function { ref decl, .. }) | + clean::TyMethodItem(clean::TyMethod { ref decl, .. }) | + clean::MethodItem(clean::Method { ref decl, .. }) | + clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => { + out = spotlight_decl(decl)?; + } + _ => {} + } + + Ok(out) +} + +fn spotlight_decl(decl: &clean::FnDecl) -> Result<String, fmt::Error> { + let mut out = String::new(); + let mut trait_ = String::new(); + + if let Some(did) = decl.output.def_id() { + let c = cache(); + if let Some(impls) = c.impls.get(&did) { + for i in impls { + let impl_ = i.inner_impl(); + if impl_.trait_.def_id().and_then(|d| c.traits.get(&d)) + .map_or(false, |t| t.is_spotlight) { + if out.is_empty() { + out.push_str( + &format!("<h3 class=\"important\">Important traits for {}</h3>\ + <code class=\"content\">", + impl_.for_)); + trait_.push_str(&format!("{}", impl_.for_)); + } + + //use the "where" class here to make it small + out.push_str(&format!("<span class=\"where fmt-newline\">{}</span>", impl_)); + let t_did = impl_.trait_.def_id().unwrap(); + for it in &impl_.items { + if let clean::TypedefItem(ref tydef, _) = it.inner { + out.push_str("<span class=\"where fmt-newline\"> "); + assoc_type(&mut out, it, &vec![], + Some(&tydef.type_), + AssocItemLink::GotoSource(t_did, &FxHashSet()))?; + out.push_str(";</span>"); + } + } + } + } + } + } + + if !out.is_empty() { + out.insert_str(0, &format!("<div class=\"important-traits\"><div class='tooltip'>ⓘ\ + <span class='tooltiptext'>Important traits for {}</span></div>\ + <div class=\"content hidden\">", + trait_)); + out.push_str("</code></div></div>"); + } + + Ok(out) +} + fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink, render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool) -> fmt::Result { @@ -3280,12 +3344,14 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi }; match item.inner { - clean::MethodItem(..) | clean::TyMethodItem(..) => { + clean::MethodItem(clean::Method { ref decl, .. }) | + clean::TyMethodItem(clean::TyMethod{ ref decl, .. }) => { // Only render when the method is not static or we allow static methods if render_method_item { let id = derive_id(format!("{}.{}", item_type, name)); let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?; + write!(w, "{}", spotlight_decl(decl)?)?; write!(w, "<span id='{}' class='invisible'>", ns_id)?; write!(w, "<code>")?; render_assoc_item(w, item, link.anchor(&id), ItemType::Impl)?; @@ -3332,6 +3398,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi if render_method_item || render_mode == RenderMode::Normal { let prefix = render_assoc_const_value(item); + if !is_default_item { if let Some(t) = trait_ { // The trait item may have been stripped so we might not diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index a3957ccdcb3..34f649aa2d3 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -216,6 +216,7 @@ var help = document.getElementById("help"); switch (getVirtualKey(ev)) { case "Escape": + hideModal(); var search = document.getElementById("search"); if (!hasClass(help, "hidden")) { displayHelp(false, ev); @@ -229,6 +230,7 @@ case "s": case "S": displayHelp(false, ev); + hideModal(); ev.preventDefault(); focusSearchBar(); break; @@ -241,6 +243,7 @@ case "?": if (ev.shiftKey) { + hideModal(); displayHelp(true, ev); } break; @@ -1713,6 +1716,31 @@ } }); + function showModal(content) { + var modal = document.createElement('div'); + modal.id = "important"; + addClass(modal, 'modal'); + modal.innerHTML = '<div class="modal-content"><div class="close" id="modal-close">✕</div>' + + '<div class="whiter"></div><span class="docblock">' + content + + '</span></div>'; + document.getElementsByTagName('body')[0].appendChild(modal); + document.getElementById('modal-close').onclick = hideModal; + modal.onclick = hideModal; + } + + function hideModal() { + var modal = document.getElementById("important"); + if (modal) { + modal.parentNode.removeChild(modal); + } + } + + onEach(document.getElementsByClassName('important-traits'), function(e) { + e.onclick = function() { + showModal(e.lastElementChild.innerHTML); + }; + }); + var search_input = document.getElementsByClassName("search-input")[0]; if (search_input) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 55acc575152..d7f4674908c 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -89,7 +89,7 @@ h2 { h3 { font-size: 1.3em; } -h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) { +h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.important), h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) { font-weight: 500; margin: 20px 0 15px 0; padding-bottom: 6px; @@ -141,9 +141,12 @@ code, pre { border-radius: 3px; padding: 0 0.2em; } -.docblock pre code, .docblock-short pre code { +.docblock pre code, .docblock-short pre code, .docblock code.spotlight { padding: 0; } +.docblock code.spotlight :last-child { + padding-bottom: 0.6em; +} pre { padding: 14px; } @@ -435,10 +438,11 @@ h4 > code, h3 > code, .invisible > code { font-size: 0.8em; } -.content .methods > div { margin-left: 40px; } +.content .methods > div:not(.important-traits) { margin-left: 40px; } .content .impl-items .docblock, .content .impl-items .stability { margin-left: 40px; + margin-bottom: .6em; } .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant { margin-left: 20px; @@ -951,3 +955,102 @@ pre.rust { color: #888; font-size: 16px; } + +.important-traits { + cursor: pointer; + z-index: 2; +} + +h4 > .important-traits { + position: absolute; + left: -44px; + top: 2px; +} + +.modal { + position: fixed; + width: 100vw; + height: 100vh; + background-color: rgba(0,0,0,0.3); + z-index: 10000; + top: 0; + left: 0; +} + +.modal-content { + display: block; + max-width: 60%; + min-width: 200px; + background-color: #eee; + padding: 8px; + top: 40%; + position: absolute; + left: 50%; + transform: translate(-50%, -40%); + border: 1px solid #999; + border-radius: 4px; + border-top-right-radius: 0; +} + +.modal-content > .docblock { + margin: 0; +} + +h3.important { + margin: 0; + margin-bottom: 13px; + font-size: 19px; +} + +.modal-content > .docblock > code.content { + margin: 0; + padding: 0; + font-size: 20px; +} + +.modal-content > .close { + position: absolute; + font-weight: 900; + right: -25px; + top: -1px; + font-size: 18px; + background-color: #eee; + width: 25px; + padding-right: 2px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + text-align: center; + border: 1px solid #999; + border-right: 0; + cursor: pointer; +} + +.modal-content > .close:hover { + background-color: #ff1f1f; + color: white; +} + +.modal-content > .whiter { + height: 25px; + position: absolute; + width: 3px; + background-color: #eee; + right: -2px; + top: 0px; +} + +.modal-content > .close:hover + .whiter { + background-color: #ff1f1f; +} + +#main > div.important-traits { + position: absolute; + left: -24px; + margin-top: 16px; +} + +.content > .methods > div.important-traits { + position: absolute; + left: -42px; + margin-top: 2px; +} \ No newline at end of file diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 62313d7d3a6..ff952122d3d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -470,6 +470,7 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> /// [`&[u8]`]: primitive.slice.html /// #[stable(feature = "rust1", since = "1.0.0")] +#[doc(spotlight)] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -988,6 +989,7 @@ impl Initializer { /// # } /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[doc(spotlight)] pub trait Write { /// Write a buffer into this object, returning how many bytes were written. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 37cc7a49b52..ccc89ccdcf4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -329,6 +329,7 @@ #![feature(vec_push_all)] #![feature(doc_cfg)] #![feature(doc_masked)] +#![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(const_atomic_ptr_new))] diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ebe7853b8ab..5c7450baa2f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -381,6 +381,8 @@ declare_features! ( (active, doc_cfg, "1.21.0", Some(43781)), // #[doc(masked)] (active, doc_masked, "1.21.0", Some(44027)), + // #[doc(spotlight)] + (active, doc_spotlight, "1.22.0", Some(45040)), // allow `#[must_use]` on functions and comparison operators (RFC 1940) (active, fn_must_use, "1.21.0", Some(43302)), @@ -1300,6 +1302,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, doc_masked, attr.span, "#[doc(masked)] is experimental" ); + } else if content.iter().any(|c| c.check_name("spotlight")) { + gate_feature_post!(&self, doc_spotlight, attr.span, + "#[doc(spotlight)] is experimental" + ); } } } diff --git a/src/test/compile-fail/feature-gate-doc_spotlight.rs b/src/test/compile-fail/feature-gate-doc_spotlight.rs new file mode 100644 index 00000000000..6369358538d --- /dev/null +++ b/src/test/compile-fail/feature-gate-doc_spotlight.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[doc(spotlight)] //~ ERROR: #[doc(spotlight)] is experimental +trait SomeTrait {} + +fn main() {} diff --git a/src/test/rustdoc/doc-spotlight.rs b/src/test/rustdoc/doc-spotlight.rs new file mode 100644 index 00000000000..a570aa2d398 --- /dev/null +++ b/src/test/rustdoc/doc-spotlight.rs @@ -0,0 +1,46 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(doc_spotlight)] + +pub struct Wrapper<T> { + inner: T, +} + +impl<T: SomeTrait> SomeTrait for Wrapper<T> {} + +#[doc(spotlight)] +pub trait SomeTrait { + // @has doc_spotlight/trait.SomeTrait.html + // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>' + fn wrap_me(self) -> Wrapper<Self> where Self: Sized { + Wrapper { + inner: self, + } + } +} + +pub struct SomeStruct; +impl SomeTrait for SomeStruct {} + +impl SomeStruct { + // @has doc_spotlight/struct.SomeStruct.html + // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' + // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>' + pub fn new() -> SomeStruct { + SomeStruct + } +} + +// @has doc_spotlight/fn.bare_fn.html +// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' +pub fn bare_fn() -> SomeStruct { + SomeStruct +} |
