Skip to main content

ferritin_common/
iterators.rs

1use crate::doc_ref::{DocRef, ParentRef};
2use fieldwork::Fieldwork;
3use rustdoc_types::{Id, Item, ItemEnum, Type, Use};
4use std::collections::hash_map::Values;
5
6pub struct MethodIter<'a> {
7    item: DocRef<'a, Item>,
8    impl_block_iter: InherentImplBlockIter<'a>,
9    current_item_iter: Option<std::slice::Iter<'a, Id>>,
10}
11
12impl<'a> MethodIter<'a> {
13    pub(crate) fn new(item: DocRef<'a, Item>) -> Self {
14        let impl_block_iter = InherentImplBlockIter::new(item);
15        Self {
16            item,
17            impl_block_iter,
18            current_item_iter: None,
19        }
20    }
21}
22
23impl<'a> DocRef<'a, Item> {
24    pub fn methods(&self) -> MethodIter<'a> {
25        MethodIter::new(*self)
26    }
27
28    pub fn traits(&self) -> TraitIter<'a> {
29        TraitIter::new(*self)
30    }
31
32    pub fn child_items(&self) -> ChildItems<'a> {
33        ChildItems::new(*self)
34    }
35}
36
37impl<'a, T> DocRef<'a, T> {
38    pub fn id_iter(&self, ids: &'a [Id]) -> IdIter<'a, T> {
39        IdIter::new(*self, ids)
40    }
41}
42
43pub struct TraitIter<'a> {
44    item: DocRef<'a, Item>,
45    item_iter: Values<'a, Id, Item>,
46}
47impl<'a> TraitIter<'a> {
48    fn new(item: DocRef<'a, Item>) -> Self {
49        let item_iter = item.crate_docs().index.values();
50        Self { item, item_iter }
51    }
52}
53
54impl<'a> Iterator for TraitIter<'a> {
55    type Item = DocRef<'a, Item>;
56
57    fn next(&mut self) -> Option<Self::Item> {
58        for item in &mut self.item_iter {
59            if let ItemEnum::Impl(impl_block) = &item.inner
60                && let Type::ResolvedPath(path) = &impl_block.for_
61                && path.id == self.item.id
62                && impl_block.trait_.is_some()
63            {
64                return Some(self.item.build_ref(item));
65            }
66        }
67        None
68    }
69}
70
71pub struct ImplementorIter<'a> {
72    trait_item: DocRef<'a, Item>,
73    item_iter: Values<'a, Id, Item>,
74}
75
76impl<'a> ImplementorIter<'a> {
77    fn new(trait_item: DocRef<'a, Item>) -> Self {
78        let item_iter = trait_item.crate_docs().index.values();
79        Self {
80            trait_item,
81            item_iter,
82        }
83    }
84}
85
86impl<'a> DocRef<'a, Item> {
87    /// Iterate impl blocks in this crate that implement this trait.
88    pub fn implementors(&self) -> ImplementorIter<'a> {
89        ImplementorIter::new(*self)
90    }
91}
92
93impl<'a> Iterator for ImplementorIter<'a> {
94    type Item = DocRef<'a, Item>;
95
96    fn next(&mut self) -> Option<Self::Item> {
97        for item in &mut self.item_iter {
98            if let ItemEnum::Impl(impl_block) = &item.inner
99                && let Some(trait_path) = &impl_block.trait_
100                && trait_path.id == self.trait_item.id
101                && !impl_block.is_negative
102            {
103                return Some(self.trait_item.build_ref(item));
104            }
105        }
106        None
107    }
108}
109
110impl<'a> Iterator for MethodIter<'a> {
111    type Item = DocRef<'a, Item>;
112
113    fn next(&mut self) -> Option<Self::Item> {
114        loop {
115            if let Some(current_item_iter) = &mut self.current_item_iter {
116                for id in current_item_iter {
117                    if let Some(item) = self.item.get(id) {
118                        return Some(item.with_parent(self.item));
119                    }
120                }
121            }
122
123            if let Some(item) = self.impl_block_iter.next()
124                && let ItemEnum::Impl(impl_block) = &item.item().inner
125            {
126                self.current_item_iter = Some(impl_block.items.iter())
127            } else {
128                return None;
129            }
130        }
131    }
132}
133
134#[derive(Debug, Fieldwork)]
135pub struct IdIter<'a, T> {
136    item: DocRef<'a, T>,
137    id_iter: std::slice::Iter<'a, Id>,
138    glob_iter: Option<Box<IdIter<'a, Item>>>,
139    #[field(with)]
140    include_use: bool,
141    #[field(with(vis = "pub(crate)", option_set_some, into))]
142    parent: Option<ParentRef<'a>>,
143}
144
145impl<'a, T> IdIter<'a, T> {
146    pub(crate) fn new(item: DocRef<'a, T>, ids: &'a [Id]) -> Self {
147        Self {
148            item,
149            id_iter: ids.iter(),
150            glob_iter: None,
151            include_use: false,
152            parent: None,
153        }
154    }
155}
156
157impl<'a, T> Iterator for IdIter<'a, T> {
158    type Item = DocRef<'a, Item>;
159
160    fn next(&mut self) -> Option<Self::Item> {
161        loop {
162            if let Some(glob_iter) = self.glob_iter.as_mut() {
163                if let Some(item) = glob_iter.next() {
164                    return Some(item);
165                } else {
166                    self.glob_iter = None;
167                }
168            }
169
170            for id in &mut self.id_iter {
171                if let Some(item) = self.item.get(id) {
172                    if let ItemEnum::Use(use_item) = item.inner() {
173                        if self.include_use {
174                            return Some(item);
175                        }
176
177                        let source_item = use_item
178                            .id
179                            .and_then(|id| item.crate_docs().get(item.navigator(), &id))
180                            .or_else(|| {
181                                item.navigator().resolve_path(&use_item.source, &mut vec![])
182                            })?;
183
184                        if use_item.is_glob {
185                            self.glob_iter = match source_item.inner() {
186                                ItemEnum::Module(module) => {
187                                    Some(Box::new(source_item.id_iter(&module.items)))
188                                }
189                                ItemEnum::Enum(enum_item) => {
190                                    Some(Box::new(source_item.id_iter(&enum_item.variants)))
191                                }
192                                _ => None,
193                            };
194
195                            break;
196                        } else {
197                            return Some(source_item.with_name(&use_item.name));
198                        }
199                    }
200                    return Some(match self.parent {
201                        Some(parent) => item.with_parent(parent),
202                        None => item,
203                    });
204                }
205            }
206            if self.glob_iter.is_none() {
207                break;
208            }
209        }
210
211        None
212    }
213}
214
215pub(crate) struct InherentImplBlockIter<'a> {
216    item: DocRef<'a, Item>,
217    item_iter: Values<'a, Id, Item>,
218}
219
220impl<'a> InherentImplBlockIter<'a> {
221    pub(crate) fn new(item: DocRef<'a, Item>) -> Self {
222        let item_iter = item.crate_docs().index.values();
223        Self { item, item_iter }
224    }
225}
226
227impl<'a> Iterator for InherentImplBlockIter<'a> {
228    type Item = DocRef<'a, Item>;
229
230    fn next(&mut self) -> Option<Self::Item> {
231        for item in &mut self.item_iter {
232            if let ItemEnum::Impl(impl_block) = &item.inner
233                && let Type::ResolvedPath(path) = &impl_block.for_
234                && path.id == self.item.id
235                && impl_block.trait_.is_none()
236            {
237                return Some(DocRef::new(self.item.navigator(), self.item, item));
238            }
239        }
240        None
241    }
242}
243
244pub enum ChildItems<'a> {
245    AssociatedMethods(MethodIter<'a>),
246    Module(IdIter<'a, Item>),
247    Use(Option<DocRef<'a, Use>>, Option<IdIter<'a, Item>>, bool),
248    Enum(IdIter<'a, Item>, MethodIter<'a>),
249    None,
250}
251
252impl<'a> Iterator for ChildItems<'a> {
253    type Item = DocRef<'a, Item>;
254
255    fn next(&mut self) -> Option<Self::Item> {
256        loop {
257            match self {
258                ChildItems::AssociatedMethods(method_iter) => return method_iter.next(),
259                ChildItems::Module(id_iter) => return id_iter.next(),
260                ChildItems::Enum(id_iter, method_iter) => {
261                    return id_iter.next().or_else(|| method_iter.next());
262                }
263                ChildItems::Use(_, Some(id_iter), _) => return id_iter.next(),
264                ChildItems::Use(use_item_option @ Some(_), id_iter @ None, include_use) => {
265                    let use_item = use_item_option.take()?;
266
267                    let name = use_item.use_name();
268
269                    let source_item = use_item
270                        .id
271                        .and_then(|id| use_item.get(&id))
272                        .or_else(|| {
273                            use_item
274                                .navigator()
275                                .resolve_path(&use_item.source, &mut vec![])
276                        })?
277                        .with_name(name);
278
279                    if use_item.is_glob {
280                        match source_item.inner() {
281                            ItemEnum::Module(module) => {
282                                *id_iter = Some(
283                                    source_item
284                                        .id_iter(&module.items)
285                                        .with_include_use(*include_use),
286                                );
287                            }
288                            ItemEnum::Enum(enum_item) => {
289                                *id_iter = Some(
290                                    source_item
291                                        .id_iter(&enum_item.variants)
292                                        .with_include_use(*include_use),
293                                );
294                            }
295                            _ => {
296                                return None;
297                            }
298                        }
299                    } else if let ItemEnum::Use(ui) = source_item.inner()
300                        && !*include_use
301                    {
302                        *use_item_option = Some(source_item.build_ref(ui));
303                    } else {
304                        return Some(source_item);
305                    }
306                }
307
308                ChildItems::Use(_, _, _) => return None,
309
310                ChildItems::None => return None,
311            }
312        }
313    }
314}
315
316impl<'a> ChildItems<'a> {
317    pub(crate) fn new(item: DocRef<'a, Item>) -> Self {
318        let parent = ParentRef::from(item);
319        match &item.item().inner {
320            ItemEnum::Module(module) => {
321                Self::Module(item.id_iter(&module.items).with_parent(parent))
322            }
323            ItemEnum::Enum(enum_item) => Self::Enum(
324                item.id_iter(&enum_item.variants).with_parent(parent),
325                item.methods(),
326            ),
327            ItemEnum::Struct(_) => Self::AssociatedMethods(item.methods()),
328            ItemEnum::Use(use_item) => ChildItems::Use(Some(item.build_ref(use_item)), None, false),
329            _ => Self::None,
330        }
331    }
332
333    pub(crate) fn with_use(self) -> Self {
334        match self {
335            ChildItems::AssociatedMethods(method_iter) => {
336                ChildItems::AssociatedMethods(method_iter)
337            }
338            ChildItems::Module(id_iter) => ChildItems::Module(id_iter.with_include_use(true)),
339            ChildItems::Enum(id_iter, method_iter) => {
340                ChildItems::Enum(id_iter.with_include_use(true), method_iter)
341            }
342            ChildItems::Use(item, Some(id_iter), _) => {
343                ChildItems::Use(item, Some(id_iter.with_include_use(true)), true)
344            }
345            ChildItems::Use(item, None, _) => ChildItems::Use(item, None, true),
346            ChildItems::None => ChildItems::None,
347        }
348    }
349}