term_rustdoc/tree/nodes/
mod.rs

1mod impls;
2pub use impls::{DImpl, DImplInner};
3
4mod structs;
5pub use structs::DStruct;
6
7mod unions;
8pub use unions::DUnion;
9
10mod enums;
11pub use enums::DEnum;
12
13mod traits;
14pub use traits::DTrait;
15
16mod imports;
17
18mod item_inner;
19pub use item_inner::DataItemKind;
20
21use super::IDMap;
22use crate::tree::{
23    impls::show::{DocTree, Show},
24    IdToID, ID,
25};
26use rustdoc_types::{Id, Item, ItemEnum, MacroKind, Module};
27use serde::{Deserialize, Serialize};
28use std::ops::Not;
29
30/// Module tree with structural items.
31/// All the items only carry ids without actual data.
32// NOTE: small improvement by turning all the types of fields
33// from Vec to Arr after instantiation.
34#[derive(Default, Serialize, Deserialize)]
35pub struct DModule {
36    pub id: ID,
37    // If true, this module is not part of the public API,
38    // but it contains items that are re-exported as public API.
39    // is_stripped: bool,
40    pub modules: Vec<DModule>,
41    pub structs: Vec<DStruct>,
42    pub unions: Vec<DUnion>,
43    pub enums: Vec<DEnum>,
44    pub traits: Vec<DTrait>,
45    pub functions: Vec<DFunction>,
46    pub constants: Vec<DConstant>,
47    pub statics: Vec<DStatic>,
48    pub type_alias: Vec<DTypeAlias>,
49    pub macros_decl: Vec<DMacroDecl>,
50    pub macros_func: Vec<DMacroFunc>,
51    pub macros_attr: Vec<DMacroAttr>,
52    pub macros_derv: Vec<DMacroDerv>,
53}
54
55impl DModule {
56    pub fn new(map: &IDMap) -> Self {
57        // root module/crate name
58        let mut index = map.indexmap().iter();
59        let (id, root) = index
60            .find_map(|(id, item)| {
61                if item.crate_id == 0 {
62                    if let ItemEnum::Module(Module {
63                        is_crate: true,
64                        items,
65                        ..
66                    }) = &item.inner
67                    {
68                        return Some((id.to_ID(), items.as_slice()));
69                    }
70                }
71                None
72            })
73            .expect("root module not found");
74
75        // module component list, used to stop a recursive reexported module
76        let mut ancestor = Vec::with_capacity(8);
77
78        let mut dmod = Self::new_inner(id, root, map, &mut ancestor);
79        dmod.sort_by_name(map);
80        dmod
81    }
82
83    fn new_inner(id: ID, inner_items: &[Id], map: &IDMap, ancestor: &mut Vec<ID>) -> Self {
84        ancestor.push(id.clone());
85        debug!(
86            "Module Paths = {:?}",
87            ancestor.iter().map(|id| map.path(id)).collect::<Vec<_>>()
88        );
89        let mut dmod = DModule {
90            id,
91            ..Default::default()
92        };
93        dmod.extract_items(inner_items, map, ancestor);
94        dmod
95    }
96
97    /// External items need external crates compiled to know details,
98    /// and the ID here is for PathMap, not IndexMap.
99    fn new_external(id: ID) -> Self {
100        DModule {
101            id,
102            ..Default::default()
103        }
104    }
105
106    fn extract_items(&mut self, inner_items: &[Id], map: &IDMap, ancestor: &mut Vec<ID>) {
107        for item_id in inner_items {
108            match map.indexmap().get(item_id) {
109                Some(item) => self.append(item, map, ancestor),
110                None => warn!("the local item {item_id:?} not found in Crate's index"),
111            }
112        }
113    }
114
115    fn append(&mut self, item: &Item, map: &IDMap, ancestor: &mut Vec<ID>) {
116        use ItemEnum::*;
117        let id = item.id.to_ID();
118        match &item.inner {
119            Module(item) => {
120                let mut kin = ancestor.clone();
121                self.modules
122                    .push(Self::new_inner(id, &item.items, map, &mut kin))
123            }
124            Struct(item) => self.structs.push(DStruct::new(id, item, map)),
125            Union(item) => self.unions.push(DUnion::new(id, item, map)),
126            Enum(item) => self.enums.push(DEnum::new(id, item, map)),
127            Trait(item) => self.traits.push(DTrait::new(id, item, map)),
128            Function(_) => self.functions.push(DFunction::new(id)),
129            Constant(_) => self.constants.push(DConstant::new(id)),
130            Static(_) => self.statics.push(DStatic::new(id)),
131            TypeAlias(_) => self.type_alias.push(DTypeAlias::new(id)),
132            Macro(_) => self.macros_decl.push(DMacroDecl::new(id)),
133            ProcMacro(proc) => match proc.kind {
134                MacroKind::Bang => self.macros_func.push(DMacroFunc::new(id)),
135                MacroKind::Attr => self.macros_attr.push(DMacroAttr::new(id)),
136                MacroKind::Derive => self.macros_derv.push(DMacroDerv::new(id)),
137            },
138            Import(import) => imports::parse_import(id, import, map, self, ancestor),
139            // Primitive(_) => todo!(),
140            _ => (),
141        }
142    }
143}
144
145macro_rules! impl_show {
146    ($( $field:ident => $tag:ident => $node:ident => $fty:ident , )+ ) => {
147/// To a recursive tree displayed with ids as nodes.
148impl Show for DModule {
149    fn show(&self) -> DocTree {
150        format!("[mod] {}", self.id).show().with_leaves(
151            std::iter::empty()
152            $(
153                .chain( impl_show!(@show $field $node $fty self map) )
154            )+
155            .chain(self.modules.iter().map(DModule::show))
156        )
157    }
158
159    fn show_prettier(&self, map: &IDMap) -> DocTree {
160        node!(Module: map, &self.id).with_leaves(
161            std::iter::empty()
162            $(
163                .chain( impl_show!(@pretty $field $node self map) )
164            )+
165            .chain(self.modules.iter().map(|m| m.show_prettier(map)))
166        )
167    }
168}
169
170impl DModule {
171    /// The main tree view as public items in module tree.
172    pub fn item_tree(&self, map: &IDMap) -> DocTree {
173        node!(Module: map, &self.id).with_leaves(
174            std::iter::empty()
175            $(
176                .chain(self.$field.iter().map(|item| {
177                    node!(@name $tag : map, &item.id)
178                }))
179            )+
180            .chain(self.modules.iter().map(|m| m.item_tree(map)))
181        )
182    }
183
184    /// sort items in their item types by name
185    fn sort_by_name(&mut self, map: &IDMap) {
186        self.modules.sort_unstable_by(|a, b| map.name(&a.id).cmp(&map.name(&b.id)));
187        self.modules.iter_mut().for_each(|m| m.sort_by_name(map));
188        $(self.$field.sort_unstable_by(|a, b| map.name(&a.id).cmp(&map.name(&b.id)));)+
189    }
190
191    /// NOTE: this method doesn't include nested modules; only returns one-level items with mod root.
192    pub fn item_tree_only_in_one_specified_mod(&self, map: &IDMap) -> DocTree {
193        node!(Module: map, &self.id).with_leaves(
194            std::iter::empty()
195            $(
196                .chain(self.$field.iter().map(|item| {
197                    node!(@name $tag : map, &item.id)
198                }))
199            )+
200        )
201    }
202}
203    };
204    (@show $field:ident $node:ident $fty:ident $self:ident $map:ident) => {
205        $self.$field.is_empty().not().then(|| {
206            $crate::tree::Tag::$node.show().with_leaves($self.$field.iter().map($fty::show))
207        })
208    };
209    (@pretty $field:ident $node:ident $self:ident $map:ident) => {
210        $self.$field.is_empty().not().then(|| {
211            $crate::tree::Tag::$node.show().with_leaves($self.$field.iter().map(|val| val.show_prettier($map)))
212        })
213    };
214}
215
216impl_show! {
217    functions   => Function  => Functions  => DFunction,
218    constants   => Constant  => Constants  => DConstant,
219    statics     => Static    => Statics    => DStatic,
220    type_alias  => TypeAlias => TypeAliass => DTypeAlias,
221    macros_decl => MacroDecl => MacroDecls => DMacroDecl,
222    macros_func => MacroFunc => MacroFuncs => DMacroFunc,
223    macros_attr => MacroAttr => MacroAttrs => DMacroAttr,
224    macros_derv => MacroDerv => MacroDervs => DMacroDerv,
225    traits      => Trait     => Traits     => DTrait,
226    structs     => Struct    => Structs    => DStruct,
227    unions      => Union     => Unions     => DUnion,
228    enums       => Enum      => Enums      => DEnum,
229}
230
231/// generate id wrapper types for simple items
232macro_rules! gen_simple_items {
233    ($( $name:ident => $tag:ident => $kind:ident , )+ ) => {$(
234        #[derive(Debug, Serialize, Deserialize)] pub struct $name { pub id: ID, }
235        impl $name { pub fn new(id: ID) -> Self { Self { id } } }
236        impl Show for $name {
237            fn show(&self) -> DocTree { self.id.show() }
238            fn show_prettier(&self, map: &IDMap) -> DocTree {
239                // node!($show, map.path(&self.id, ItemKind::$kind))
240                node!(@name $tag: map, &self.id)
241            }
242        }
243    )+};
244}
245
246gen_simple_items! {
247    DFunction  => Function  => Function,
248    DConstant  => Constant  => Constant,
249    DStatic    => Static    => Static,
250    DTypeAlias => TypeAlias => TypeAlias,
251    DMacroDecl => MacroDecl => Macro,
252    DMacroFunc => MacroFunc => Macro,
253    DMacroAttr => MacroAttr => ProcAttribute,
254    DMacroDerv => MacroDerv => ProcDerive,
255}
256
257// TODO:
258// *  structs, enums, and enum variants: [non_exhaustive]
259//
260// [non_exhaustive]: https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute