about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-01-25 15:43:29 +0000
committerbors <bors@rust-lang.org>2022-01-25 15:43:29 +0000
commit92ed8747f255b2695c33b64982e6959711a72cb9 (patch)
tree2d93b34de6249b0f75fd8862846dcd545825407c
parent17dfae79bbc3dabe1427073086acf7f7bd45148c (diff)
parent3a3e4b78593bc2669828dfc2e36070897b9c6a4d (diff)
downloadrust-92ed8747f255b2695c33b64982e6959711a72cb9.tar.gz
rust-92ed8747f255b2695c33b64982e6959711a72cb9.zip
Auto merge of #92353 - Kobzol:doc-attr-lists-gat, r=GuillaumeGomez
Rustdoc: remove ListAttributesIter and use impl Iterator instead

This is a continuation of https://github.com/rust-lang/rust/pull/92227.

I found that `ListAttributesIter` did not optimize well and replacing it with a simple `impl Iterator` resulted in 1-3 % instruction count wins locally.

Because I needed to use `impl Iterator` on a slice of AST attributes, I had to implement it using GAT + impl trait. I also have a version without GAT [here](https://github.com/Kobzol/rust/commit/5470e2a65cbd3086d19f0847f44ca9cbbc049689), if GATs are not welcome in rustdoc :D Locally it resulted in equal performance numbers.

Can I ask for a perf. run? Thanks.

r? rust-lang/rustdoc
-rw-r--r--src/librustdoc/clean/types.rs63
-rw-r--r--src/librustdoc/lib.rs2
2 files changed, 19 insertions, 46 deletions
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 0c0787c6b2f..dac23691a30 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -5,7 +5,7 @@ use std::lazy::SyncOnceCell as OnceCell;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
-use std::{slice, vec};
+use std::vec;
 
 use arrayvec::ArrayVec;
 
@@ -733,43 +733,12 @@ crate struct Module {
     crate span: Span,
 }
 
-crate struct ListAttributesIter<'a> {
-    attrs: slice::Iter<'a, ast::Attribute>,
-    current_list: vec::IntoIter<ast::NestedMetaItem>,
-    name: Symbol,
-}
-
-impl<'a> Iterator for ListAttributesIter<'a> {
-    type Item = ast::NestedMetaItem;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if let Some(nested) = self.current_list.next() {
-            return Some(nested);
-        }
-
-        for attr in &mut self.attrs {
-            if let Some(list) = attr.meta_item_list() {
-                if attr.has_name(self.name) {
-                    self.current_list = list.into_iter();
-                    if let Some(nested) = self.current_list.next() {
-                        return Some(nested);
-                    }
-                }
-            }
-        }
-
-        None
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let lower = self.current_list.len();
-        (lower, None)
-    }
-}
-
 crate trait AttributesExt {
-    /// Finds an attribute as List and returns the list of attributes nested inside.
-    fn lists(&self, name: Symbol) -> ListAttributesIter<'_>;
+    type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem>
+    where
+        Self: 'a;
+
+    fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a>;
 
     fn span(&self) -> Option<rustc_span::Span>;
 
@@ -781,8 +750,13 @@ crate trait AttributesExt {
 }
 
 impl AttributesExt for [ast::Attribute] {
-    fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
-        ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), name }
+    type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
+
+    fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
+        self.iter()
+            .filter(move |attr| attr.has_name(name))
+            .filter_map(ast::Attribute::meta_item_list)
+            .flatten()
     }
 
     /// Return the span of the first doc-comment, if it exists.
@@ -902,12 +876,9 @@ crate trait NestedAttributesExt {
     fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
 }
 
-impl<I> NestedAttributesExt for I
-where
-    I: IntoIterator<Item = ast::NestedMetaItem>,
-{
-    fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem> {
-        self.into_iter().find(|attr| attr.is_word() && attr.has_name(word))
+impl<I: Iterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
+    fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
+        self.find(|attr| attr.is_word() && attr.has_name(word))
     }
 }
 
@@ -1015,7 +986,7 @@ crate struct Attributes {
 }
 
 impl Attributes {
-    crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
+    crate fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::NestedMetaItem> + '_ {
         self.other_attrs.lists(name)
     }
 
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index d854aa86b3a..a7c3c0bb606 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -16,6 +16,8 @@
 #![feature(once_cell)]
 #![feature(type_ascription)]
 #![feature(iter_intersperse)]
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
 #![recursion_limit = "256"]
 #![warn(rustc::internal)]
 #![allow(clippy::collapsible_if, clippy::collapsible_else_if)]