1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
pub mod relation;
pub mod state;

pub use self::state::ItemState;

use std::rc::Rc;
use std::{iter, slice};

use rustc_ast::{ast, ptr};

use crate::module::path::ModulePath;

/// The structure Item is a iterable collection of abstract elements.

#[derive(Debug, Clone)]
pub struct Item<'a> {
    /// Iterator.
    it: iter::Peekable<slice::Iter<'a, (ptr::P<ast::Item>, Rc<ModulePath>)>>,
}

impl<'a> From<iter::Peekable<slice::Iter<'a, (ptr::P<ast::Item>, Rc<ModulePath>)>>> for Item<'a> {
    /// The constructor method `from` returns a typed and iterable collection of abstract element.
    fn from(iter: iter::Peekable<slice::Iter<'a, (ptr::P<ast::Item>, Rc<ModulePath>)>>) -> Item {
        Item { it: iter }
    }
}

impl<'a> Iterator for Item<'a> {
    type Item = ItemState<'a>;

    /// The method `next` will returns the first abstract elements defined like a structure,
    /// enumeration or trait.
    fn next(&mut self) -> Option<ItemState<'a>> {
        self.it.next().and_then(|item| {
            let mut list: Vec<&'a (ptr::P<ast::Item>, Rc<ModulePath>)> = vec![item];

            // Loop over all Items to find any Impl with a name that matches our name.
            // This way we can handle cases like:
            //      struct Foo{}
            //      struct Bar{}
            //      impl Foo {...}
            //      impl Bar {...}
            //      impl Foo {...}
            let item_name = &item.0.ident.name;
            list.extend(
                self.it
                    .clone()
                    .filter(
                        |&&(ref subitem, _): &&'a (ptr::P<ast::Item>, Rc<ModulePath>)| {
                            if let &ast::ItemKind::Impl(box ast::Impl {
                                self_ty: ref ty, ..
                            }) = &subitem.kind
                            {
                                if let &ast::Ty {
                                    kind:
                                        ast::TyKind::Path(
                                            _,
                                            ast::Path {
                                                segments: ref seg, ..
                                            },
                                        ),
                                    ..
                                } = &**ty
                                {
                                    if !seg.is_empty() && &seg[0].ident.name == item_name {
                                        return true;
                                    }
                                }
                            }
                            false
                        },
                    )
                    .collect::<Vec<&'a (ptr::P<ast::Item>, Rc<ModulePath>)>>(),
            );
            Some(ItemState::from(list))
        })
    }
}