From 89aa04299451baf73750c8480d14471dfced44db Mon Sep 17 00:00:00 2001
From: Georg Brandl <georg@python.org>
Date: Tue, 3 May 2016 19:15:59 +0200
Subject: [PATCH 1/3] rustdoc: add "src" links to individual impls

Since these impls can be scattered around quite a bit, it is nice
to be able to jump to the location where individual methods and
trait impls are defined.

Fixes: #30416
---
 src/librustdoc/html/render.rs | 98 +++++++++++++++++++++--------------
 1 file changed, 59 insertions(+), 39 deletions(-)

diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 5cdddc76582b3..96a9315599f9a 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -145,14 +145,19 @@ pub struct Implementor {
 /// Metadata about implementations for a type.
 #[derive(Clone)]
 pub struct Impl {
-    pub impl_: clean::Impl,
-    pub dox: Option<String>,
-    pub stability: Option<clean::Stability>,
+    pub impl_item: clean::Item,
 }
 
 impl Impl {
+    fn inner_impl(&self) -> &clean::Impl {
+        match self.impl_item.inner {
+            clean::ImplItem(ref impl_) => impl_,
+            _ => panic!("non-impl item found in impl")
+        }
+    }
+
     fn trait_did(&self) -> Option<DefId> {
-        self.impl_.trait_.def_id()
+        self.inner_impl().trait_.def_id()
     }
 }
 
@@ -1189,31 +1194,34 @@ impl DocFolder for Cache {
         // Once we've recursively found all the generics, then hoard off all the
         // implementations elsewhere
         let ret = self.fold_item_recur(item).and_then(|item| {
-            if let clean::Item { attrs, inner: clean::ImplItem(i), .. } = item {
+            if let clean::Item { inner: clean::ImplItem(_), .. } = item {
                 // Figure out the id of this impl. This may map to a
                 // primitive rather than always to a struct/enum.
-                let did = match i.for_ {
-                    clean::ResolvedPath { did, .. } |
-                    clean::BorrowedRef {
-                        type_: box clean::ResolvedPath { did, .. }, ..
-                    } => {
-                        Some(did)
-                    }
-                    ref t => {
-                        t.primitive_type().and_then(|t| {
-                            self.primitive_locations.get(&t).map(|n| {
-                                let id = t.to_def_index();
-                                DefId { krate: *n, index: id }
+                // Note: matching twice to restrict the lifetime of the `i` borrow.
+                let did = if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
+                    match i.for_ {
+                        clean::ResolvedPath { did, .. } |
+                        clean::BorrowedRef {
+                            type_: box clean::ResolvedPath { did, .. }, ..
+                        } => {
+                            Some(did)
+                        }
+                        ref t => {
+                            t.primitive_type().and_then(|t| {
+                                self.primitive_locations.get(&t).map(|n| {
+                                    let id = t.to_def_index();
+                                    DefId { krate: *n, index: id }
+                                })
                             })
-                        })
+                        }
                     }
+                } else {
+                    unreachable!()
                 };
                 if !self.seen_mod {
                     if let Some(did) = did {
                         self.impls.entry(did).or_insert(vec![]).push(Impl {
-                            impl_: i,
-                            dox: attrs.value("doc").map(|s|s.to_owned()),
-                            stability: item.stability.clone(),
+                            impl_item: item,
                         });
                     }
                 }
@@ -1510,11 +1518,15 @@ impl<'a> Item<'a> {
         // located, then we return `None`.
         } else {
             let cache = cache();
-            let path = &cache.external_paths[&self.item.def_id];
-            let root = match cache.extern_locations[&self.item.def_id.krate] {
-                (_, Remote(ref s)) => s.to_string(),
-                (_, Local) => self.cx.root_path.clone(),
-                (_, Unknown) => return None,
+            let path = match cache.external_paths.get(&self.item.def_id) {
+                Some(path) => path,
+                None => return None,
+            };
+            let root = match cache.extern_locations.get(&self.item.def_id.krate) {
+                Some(&(_, Remote(ref s))) => s.to_string(),
+                Some(&(_, Local)) => self.cx.root_path.clone(),
+                Some(&(_, Unknown)) => return None,
+                None => return None,
             };
             Some(format!("{root}{path}/{file}?gotosrc={goto}",
                          root = root,
@@ -2449,7 +2461,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
         None => return Ok(()),
     };
     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| {
-        i.impl_.trait_.is_none()
+        i.inner_impl().trait_.is_none()
     });
     if !non_trait.is_empty() {
         let render_header = match what {
@@ -2473,7 +2485,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
     }
     if !traits.is_empty() {
         let deref_impl = traits.iter().find(|t| {
-            t.impl_.trait_.def_id() == c.deref_trait_did
+            t.inner_impl().trait_.def_id() == c.deref_trait_did
         });
         if let Some(impl_) = deref_impl {
             render_deref_methods(w, cx, impl_, containing_item)?;
@@ -2481,11 +2493,11 @@ fn render_assoc_items(w: &mut fmt::Formatter,
         write!(w, "<h2 id='implementations'>Trait \
                    Implementations</h2>")?;
         let (derived, manual): (Vec<_>, Vec<&Impl>) = traits.iter().partition(|i| {
-            i.impl_.derived
+            i.inner_impl().derived
         });
         for i in &manual {
             let did = i.trait_did().unwrap();
-            let assoc_link = AssocItemLink::GotoSource(did, &i.impl_.provided_trait_methods);
+            let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
             render_impl(w, cx, i, assoc_link, true, containing_item.stable_since())?;
         }
         if !derived.is_empty() {
@@ -2494,7 +2506,8 @@ fn render_assoc_items(w: &mut fmt::Formatter,
                        </h3>")?;
             for i in &derived {
                 let did = i.trait_did().unwrap();
-                let assoc_link = AssocItemLink::GotoSource(did, &i.impl_.provided_trait_methods);
+                let assoc_link = AssocItemLink::GotoSource(did,
+                                                           &i.inner_impl().provided_trait_methods);
                 render_impl(w, cx, i, assoc_link, true, containing_item.stable_since())?;
             }
         }
@@ -2504,8 +2517,8 @@ fn render_assoc_items(w: &mut fmt::Formatter,
 
 fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
                         container_item: &clean::Item) -> fmt::Result {
-    let deref_type = impl_.impl_.trait_.as_ref().unwrap();
-    let target = impl_.impl_.items.iter().filter_map(|item| {
+    let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
+    let target = impl_.inner_impl().items.iter().filter_map(|item| {
         match item.inner {
             clean::TypedefItem(ref t, true) => Some(&t.type_),
             _ => None,
@@ -2531,11 +2544,18 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
 fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink,
                render_header: bool, outer_version: Option<&str>) -> fmt::Result {
     if render_header {
-        write!(w, "<h3 class='impl'><code>{}</code>", i.impl_)?;
-        let since = i.stability.as_ref().map(|s| &s.since[..]);
+        write!(w, "<h3 class='impl'><span class='in-band'><code>{}</code>", i.inner_impl())?;
+        let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
         render_stability_since_raw(w, since, outer_version)?;
-        write!(w, "</h3>")?;
-        if let Some(ref dox) = i.dox {
+        write!(w, "</span><span class='out-of-band'>")?;
+        if let Some(l) = (Item { item: &i.impl_item, cx: cx }).href() {
+            write!(w, "<a id='src-{}' class='srclink' \
+                       href='{}' title='{}'>[src]</a>",
+                   i.impl_item.def_id.index.as_usize(), l, "goto source code")?;
+        }
+        write!(w, "</span>")?;
+        write!(w, "</h3>\n")?;
+        if let Some(ref dox) = i.impl_item.attrs.value("doc") {
             write!(w, "<div class='docblock'>{}</div>", Markdown(dox))?;
         }
     }
@@ -2601,7 +2621,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
     }
 
     write!(w, "<div class='impl-items'>")?;
-    for trait_item in &i.impl_.items {
+    for trait_item in &i.inner_impl().items {
         doctraititem(w, cx, trait_item, link, render_header, false, outer_version)?;
     }
 
@@ -2629,7 +2649,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
     // default items which weren't overridden in the implementation block.
     if let Some(did) = i.trait_did() {
         if let Some(t) = cache().traits.get(&did) {
-            render_default_items(w, cx, t, &i.impl_, render_header, outer_version)?;
+            render_default_items(w, cx, t, &i.inner_impl(), render_header, outer_version)?;
         }
     }
     write!(w, "</div>")?;

From 083c3952e0d5473cd5c41a9eb7b4ffca18cc8e5f Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Thu, 5 May 2016 04:46:45 +0200
Subject: [PATCH 2/3] Update CSS for future rustdoc merge

---
 src/librustdoc/html/static/rustdoc.css | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index c07871a4029ca..94b59fe2addfd 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -270,6 +270,11 @@ nav.sub {
     padding: 0px;
     text-align: right;
     display: inline-block;
+    font-weight: normal;
+}
+
+h3.impl > .out-of-band {
+    font-size: 21px;
 }
 
 .content .in-band {

From cdca0843779eed0b9046e9fee48c91458ad51605 Mon Sep 17 00:00:00 2001
From: ggomez <guillaume1.gomez@gmail.com>
Date: Fri, 6 May 2016 18:47:12 +0200
Subject: [PATCH 3/3] Improve rustdoc css of "source" and "since" elements

---
 src/librustdoc/html/render.rs              |  9 +++--
 src/librustdoc/html/static/rustdoc.css     | 38 +++++++++++++++++++---
 src/librustdoc/html/static/styles/main.css |  3 ++
 3 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 96a9315599f9a..4c652f54009da 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2144,7 +2144,7 @@ fn render_stability_since_raw<'a>(w: &mut fmt::Formatter,
                                   containing_ver: Option<&'a str>) -> fmt::Result {
     if let Some(v) = ver {
         if containing_ver != ver && v.len() > 0 {
-            write!(w, "<span class=\"since\">{}</span>",
+            write!(w, "<div class=\"since\">{}</div>",
                    v)?
         }
     }
@@ -2545,13 +2545,16 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                render_header: bool, outer_version: Option<&str>) -> fmt::Result {
     if render_header {
         write!(w, "<h3 class='impl'><span class='in-band'><code>{}</code>", i.inner_impl())?;
-        let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
-        render_stability_since_raw(w, since, outer_version)?;
         write!(w, "</span><span class='out-of-band'>")?;
+        let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
         if let Some(l) = (Item { item: &i.impl_item, cx: cx }).href() {
+            write!(w, "<div class='ghost'></div>")?;
+            render_stability_since_raw(w, since, outer_version)?;
             write!(w, "<a id='src-{}' class='srclink' \
                        href='{}' title='{}'>[src]</a>",
                    i.impl_item.def_id.index.as_usize(), l, "goto source code")?;
+        } else {
+            render_stability_since_raw(w, since, outer_version)?;
         }
         write!(w, "</span>")?;
         write!(w, "</h3>\n")?;
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 94b59fe2addfd..4d65b91ed421c 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -97,6 +97,7 @@ h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):no
 h1.fqn {
     border-bottom: 1px dashed;
     margin-top: 0;
+    position: relative;
 }
 h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
     border-bottom: 1px solid;
@@ -105,6 +106,7 @@ h3.impl, h3.method, h4.method, h3.type, h4.type {
     font-weight: 600;
     margin-top: 10px;
     margin-bottom: 10px;
+    position: relative;
 }
 h3.impl, h3.method, h3.type {
     margin-top: 15px;
@@ -265,25 +267,39 @@ nav.sub {
 
 .content .out-of-band {
     font-size: 23px;
-    width: 40%;
     margin: 0px;
     padding: 0px;
     text-align: right;
     display: inline-block;
     font-weight: normal;
+    position: absolute;
+    right: 0;
 }
 
 h3.impl > .out-of-band {
     font-size: 21px;
 }
 
+h4 > code, h3 > code {
+    position: inherit;
+}
+
+.in-band, code {
+    z-index: 5;
+}
+
 .content .in-band {
-    width: 60%;
     margin: 0px;
     padding: 0px;
     display: inline-block;
 }
 
+#main { position: relative; }
+#main > .since {
+    top: inherit;
+    font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
 .content table {
     border-spacing: 0 5px;
     border-collapse: separate;
@@ -503,11 +519,13 @@ em.stab p {
     opacity: 0.65;
 }
 
-span.since {
-    float: right;
+.since {
     font-weight: normal;
     font-size: initial;
     color: grey;
+    position: absolute;
+    right: 0;
+    top: 0;
 }
 
 .variants_table {
@@ -602,7 +620,19 @@ a.test-arrow {
     color: #999;
 }
 
+.ghost {
+    display: none;
+}
+
+.ghost + .since {
+    position: initial;
+    display: table-cell;
+}
 
+.since + .srclink {
+    display: table-cell;
+    padding-left: 10px;
+}
 
 /* Media Queries */
 
diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css
index 5c073860f08ca..59b2ff7e3d649 100644
--- a/src/librustdoc/html/static/styles/main.css
+++ b/src/librustdoc/html/static/styles/main.css
@@ -26,6 +26,9 @@ h1.fqn {
 h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) {
     border-bottom-color: #DDDDDD;
 }
+.in-band, code {
+    background-color: white;
+}
 
 .docblock code {
     background-color: #F5F5F5;