term_rustdoc/tree/nodes/
impls.rs

1use crate::tree::{
2    impls::show::{show_ids, show_names, DocTree, Show},
3    IDMap, IDs, IdToID, Tag, ID,
4};
5use itertools::Itertools;
6use rustdoc_types::{Id, Impl, ItemEnum};
7use serde::{Deserialize, Serialize};
8
9/// All elements in slice are ordered by name.
10#[derive(Clone, Default, Deserialize, Serialize)]
11pub struct DImpl {
12    pub inherent: Box<[DImplInner]>,
13    pub trait_: Box<[DImplInner]>,
14    pub auto: Box<[DImplInner]>,
15    pub blanket: Box<[DImplInner]>,
16    /// Inherent items from multiple impl blocks are merged into one block
17    /// with themselves sorted by name.
18    ///
19    /// NOTE: the impl block id is empty and invalid!
20    pub merged_inherent: Box<DImplInner>,
21}
22
23impl DImpl {
24    pub fn new(ids: &[Id], map: &IDMap) -> Self {
25        if ids.is_empty() {
26            return Default::default();
27        }
28        let [mut inherent, mut trait_, mut auto, mut blanket]: [Vec<_>; 4] = Default::default();
29        for Id(id) in ids {
30            let id = id.as_str();
31            if id.starts_with("a:") {
32                auto.push(DImplInner::new_with_no_details(id));
33            } else if id.starts_with("b:") {
34                blanket.push(DImplInner::new_with_no_details(id));
35            } else if let Some(item) = map.get_item(id) {
36                if let ItemEnum::Impl(impl_) = &item.inner {
37                    if impl_.trait_.is_none() {
38                        inherent.push(DImplInner::new(id, impl_, map));
39                    } else {
40                        trait_.push(DImplInner::new(id, impl_, map));
41                    }
42                } else {
43                    warn!("{id:?} in Crate's index doesn't refer to an impl item");
44                }
45            } else {
46                warn!("the impl with {id:?} not found in Crate's index");
47            }
48        }
49        inherent.sort_unstable_by_key(|x| map.name(&x.id));
50        trait_.sort_unstable_by_key(|x| map.name(&x.id));
51        auto.sort_unstable_by_key(|x| map.name(&x.id));
52        blanket.sort_unstable_by_key(|x| map.name(&x.id));
53        let merged_inherent = DImplInner::merge_inherent_impls(&inherent, map);
54        DImpl {
55            inherent: inherent.into(),
56            trait_: trait_.into(),
57            auto: auto.into(),
58            blanket: blanket.into(),
59            merged_inherent: Box::new(merged_inherent),
60        }
61    }
62    pub fn is_empty(&self) -> bool {
63        self.auto.is_empty()
64            && self.blanket.is_empty()
65            && self.inherent.is_empty()
66            && self.trait_.is_empty()
67    }
68}
69
70impl Show for DImpl {
71    fn show(&self) -> DocTree {
72        "Implementations".show().with_leaves([
73            "Inherent Impls"
74                .show()
75                .with_leaves(self.inherent.iter().map(|i| i.show())),
76            "Trait Impls"
77                .show()
78                .with_leaves(self.trait_.iter().map(|i| i.show())),
79            "Auto Impls"
80                .show()
81                .with_leaves(self.auto.iter().map(|i| i.show())),
82            "Blanket Impls"
83                .show()
84                .with_leaves(self.blanket.iter().map(|i| i.show())),
85        ])
86    }
87
88    fn show_prettier(&self, map: &IDMap) -> DocTree {
89        if self.is_empty() {
90            return Tag::NoImpls.show();
91        }
92        let mut root = Tag::Implementations.show();
93        if !self.merged_inherent.is_empty() {
94            let tree = Tag::InherentImpls.show();
95            // let tag = Tag::ImplInherent;
96            // root.push(tree.with_leaves(self.inherent.iter().map(|i| i.show_prettier(tag, map))));
97            root.push(tree.with_leaves(self.merged_inherent.show_prettier_iter(map)));
98        }
99        if !self.trait_.is_empty() {
100            let tree = Tag::TraitImpls.show();
101            let tag = Tag::ImplTrait;
102            root.push(tree.with_leaves(self.trait_.iter().map(|i| i.show_prettier(tag, map))));
103        }
104        if !self.auto.is_empty() {
105            let tree = Tag::AutoImpls.show();
106            let tag = Tag::ImplAuto;
107            root.push(tree.with_leaves(self.auto.iter().map(|i| i.show_prettier(tag, map))));
108        }
109        if !self.blanket.is_empty() {
110            let tree = Tag::BlanketImpls.show();
111            let tag = Tag::ImplBlanket;
112            root.push(tree.with_leaves(self.blanket.iter().map(|i| i.show_prettier(tag, map))));
113        }
114        root
115    }
116}
117
118#[derive(Clone, Default, Deserialize, Serialize)]
119pub struct DImplInner {
120    pub id: ID,
121    pub functions: IDs,
122    pub constants: IDs,
123    pub types: IDs,
124}
125
126impl DImplInner {
127    pub fn new(id: &str, imp: &Impl, map: &IDMap) -> Self {
128        let [mut functions, mut constants, mut types]: [Vec<ID>; 3] = Default::default();
129        for item in imp.items.iter().flat_map(|assc| map.get_item(&assc.0)) {
130            match &item.inner {
131                ItemEnum::Function(_) => functions.push(item.id.to_ID()),
132                ItemEnum::Constant(_) => constants.push(item.id.to_ID()),
133                ItemEnum::TypeAlias(_) => types.push(item.id.to_ID()),
134                _ => (),
135            };
136        }
137        functions.sort_unstable_by_key(|id| map.name(id));
138        constants.sort_unstable_by_key(|id| map.name(id));
139        types.sort_unstable_by_key(|id| map.name(id));
140        DImplInner {
141            id: id.to_ID(),
142            functions: functions.into(),
143            constants: constants.into(),
144            types: types.into(),
145        }
146    }
147
148    pub fn new_with_no_details(id: &str) -> Self {
149        DImplInner {
150            id: id.to_ID(),
151            ..Default::default()
152        }
153    }
154
155    fn show(&self) -> DocTree {
156        let mut root = self.id.show();
157        if !self.functions.is_empty() {
158            root.push("Functions".show().with_leaves(show_ids(&self.functions)));
159        }
160        if !self.constants.is_empty() {
161            root.push("Constants".show().with_leaves(show_ids(&self.constants)));
162        }
163        if !self.types.is_empty() {
164            root.push("Types".show().with_leaves(show_ids(&self.types)));
165        }
166        root
167    }
168
169    fn show_prettier(&self, tag: Tag, map: &IDMap) -> DocTree {
170        let root = DocTree::new(map.name(&self.id), tag, Some(self.id.as_str().into()));
171        // too verbose!
172        // let leaves = names_node!(
173        //     self map root,
174        //     Functions  functions Function,
175        //     Constants  constants Constant,
176        //     TypeAliass types     TypeAlias,
177        // );
178        root.with_leaves(self.show_prettier_iter(map))
179    }
180
181    /// mainly for inherent impls
182    fn show_prettier_iter<'s: 'ret, 'map: 'ret, 'ret>(
183        &'s self,
184        map: &'map IDMap,
185    ) -> impl 'ret + Iterator<Item = DocTree> {
186        show_names(&*self.constants, Tag::Constant, map)
187            .chain(show_names(&*self.types, Tag::TypeAlias, map))
188            .chain(show_names(&*self.functions, Tag::Function, map))
189    }
190
191    fn merge_inherent_impls(impls: &[Self], map: &IDMap) -> Self {
192        let iter = impls.iter();
193        Self {
194            id: ID::default(),
195            functions: iter
196                .clone()
197                .flat_map(|x| x.functions.iter())
198                .sorted_unstable_by_key(|id| map.name(id))
199                .cloned()
200                .collect(),
201            constants: iter
202                .clone()
203                .flat_map(|x| x.constants.iter())
204                .sorted_unstable_by_key(|id| map.name(id))
205                .cloned()
206                .collect(),
207            types: iter
208                .flat_map(|x| x.types.iter())
209                .sorted_unstable_by_key(|id| map.name(id))
210                .cloned()
211                .collect(),
212        }
213    }
214
215    fn is_empty(&self) -> bool {
216        self.functions.is_empty() && self.constants.is_empty() && self.types.is_empty()
217    }
218}