crate_inspector/
lib.rs

1pub mod format;
2
3use std::io::Write;
4use std::ops::Deref;
5use std::path::Path;
6
7use rustdoc_json::Color;
8use rustdoc_types::{Id, Type};
9
10pub trait CrateItem<'a> {
11    type Inner;
12    fn downcast(inner: &'a rustdoc_types::ItemEnum) -> Option<&'a Self::Inner>;
13    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, inner: &'a Self::Inner) -> Self;
14    fn krate(&self) -> &'a Crate;
15    fn item(&self) -> &'a rustdoc_types::Item;
16    fn inner(&self) -> &'a Self::Inner;
17    fn is_public(&self) -> bool {
18        self.item().visibility == rustdoc_types::Visibility::Public
19    }
20    fn is_crate_item(&self) -> bool {
21        self.item().crate_id == 0
22    }
23    fn is_root_item(&self) -> bool {
24        self.module()
25            .is_some_and(|module| module.id() == &self.krate().root)
26    }
27    fn is_external_item(&self) -> bool {
28        self.item().crate_id != 0
29    }
30    fn id(&'a self) -> &'a Id {
31        &self.item().id
32    }
33    fn module(&self) -> Option<ModuleItem<'a>> {
34        self.krate()
35            .all_modules()
36            .find(|module| module.module.items.contains(&self.item().id))
37    }
38}
39
40pub trait HasType {
41    fn type_(&self) -> &Type;
42}
43
44pub trait HasName {
45    fn name(&self) -> &str;
46}
47
48macro_rules! impl_items {
49    ($ty: ident < $l: lifetime >) => {
50        impl<$l> $ty<$l> {
51            pub fn constants(&self) -> impl Iterator<Item = ConstantItem<'_>> {
52                self.items()
53                    .filter_map(|item| self.krate().downcast::<ConstantItem>(item))
54            }
55
56            pub fn functions(&self) -> impl Iterator<Item = FunctionItem<'_>> {
57                self.items()
58                    .filter_map(|item| self.krate().downcast::<FunctionItem>(item))
59            }
60
61            pub fn structs(&self) -> impl Iterator<Item = StructItem<'_>> {
62                self.items()
63                    .filter_map(|item| self.krate().downcast::<StructItem>(item))
64            }
65
66            pub fn enums(&self) -> impl Iterator<Item = EnumItem<'_>> {
67                self.items()
68                    .filter_map(|item| self.krate().downcast::<EnumItem>(item))
69            }
70
71            pub fn traits(&self) -> impl Iterator<Item = TraitItem<'_>> {
72                self.items()
73                    .filter_map(|item| self.krate().downcast::<TraitItem>(item))
74            }
75
76            pub fn type_aliases(&self) -> impl Iterator<Item = TypeAliasItem<'_>> {
77                self.items()
78                    .filter_map(|item| self.krate().downcast::<TypeAliasItem>(item))
79            }
80
81            pub fn trait_aliases(&self) -> impl Iterator<Item = TraitAliasItem<'_>> {
82                self.items()
83                    .filter_map(|item| self.krate().downcast::<TraitAliasItem>(item))
84            }
85
86            pub fn unions(&self) -> impl Iterator<Item = UnionItem<'_>> {
87                self.items()
88                    .filter_map(|item| self.krate().downcast::<UnionItem>(item))
89            }
90
91            pub fn modules(&self) -> impl Iterator<Item = ModuleItem<'_>> {
92                self.items()
93                    .filter_map(|item| self.krate().downcast::<ModuleItem>(item))
94            }
95
96            pub fn impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
97                self.items()
98                    .filter_map(|item| self.krate().downcast::<ImplItem>(item))
99            }
100
101            pub fn uses(&self) -> impl Iterator<Item = UseItem<'_>> {
102                self.items()
103                    .filter_map(|item| self.krate().downcast::<UseItem>(item))
104            }
105
106            /// Get an item by its name.
107            pub fn get_item(&self, name: &str) -> Option<&rustdoc_types::Item> {
108                self.items()
109                    .find(|item| item.name.as_ref().is_some_and(|n| n == name))
110            }
111
112            /// Get a constant by its name.
113            pub fn get_constant(&self, name: &str) -> Option<ConstantItem<'_>> {
114                self.constants().find(|constant| constant.name() == name)
115            }
116
117            /// Get a function by its name.
118            pub fn get_function(&self, name: &str) -> Option<FunctionItem<'_>> {
119                self.functions().find(|func| func.name() == name)
120            }
121
122            /// Get a struct by its name.
123            pub fn get_struct(&self, name: &str) -> Option<StructItem<'_>> {
124                self.structs().find(|struct_| struct_.name() == name)
125            }
126
127            /// Get an enum by its name.
128            pub fn get_enum(&self, name: &str) -> Option<EnumItem<'_>> {
129                self.enums().find(|enum_| enum_.name() == name)
130            }
131
132            /// Get a trait by its name.
133            pub fn get_trait(&self, name: &str) -> Option<TraitItem<'_>> {
134                self.traits().find(|trait_| trait_.name() == name)
135            }
136
137            /// Get a type alias by its name.
138            pub fn get_type_alias(&self, name: &str) -> Option<TypeAliasItem<'_>> {
139                self.type_aliases()
140                    .find(|type_alias| type_alias.name() == name)
141            }
142
143            /// Get a trait alias by its name.
144            pub fn get_trait_alias(&self, name: &str) -> Option<TraitAliasItem<'_>> {
145                self.trait_aliases()
146                    .find(|trait_alias| trait_alias.name() == name)
147            }
148
149            /// Get a union by its name.
150            pub fn get_union(&self, name: &str) -> Option<UnionItem<'_>> {
151                self.unions().find(|union| union.name() == name)
152            }
153
154            /// Get a module by its name.
155            pub fn get_module(&self, name: &str) -> Option<ModuleItem<'_>> {
156                self.modules().find(|module| module.name() == name)
157            }
158        }
159    };
160}
161
162#[derive(Debug, Copy, Clone, PartialEq, Eq)]
163pub struct ModuleItem<'a> {
164    krate: &'a Crate,
165    item: &'a rustdoc_types::Item,
166    module: &'a rustdoc_types::Module,
167}
168
169impl<'a> CrateItem<'a> for ModuleItem<'a> {
170    type Inner = rustdoc_types::Module;
171    fn downcast(inner: &'a rustdoc_types::ItemEnum) -> Option<&'a Self::Inner> {
172        match inner {
173            rustdoc_types::ItemEnum::Module(module) => Some(module),
174            _ => None,
175        }
176    }
177    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, module: &'a Self::Inner) -> Self {
178        Self {
179            krate,
180            item,
181            module,
182        }
183    }
184    fn item(&self) -> &'a rustdoc_types::Item {
185        self.item
186    }
187    fn inner(&self) -> &'a Self::Inner {
188        self.module
189    }
190    fn krate(&self) -> &'a Crate {
191        self.krate
192    }
193}
194
195impl HasName for ModuleItem<'_> {
196    fn name(&self) -> &str {
197        self.item.name.as_ref().unwrap()
198    }
199}
200
201impl<'a> ModuleItem<'a> {
202    pub fn name(&self) -> &str {
203        self.item.name.as_ref().unwrap()
204    }
205
206    pub fn item_ids(&self) -> impl Iterator<Item = &Id> {
207        self.module.items.iter()
208    }
209
210    pub fn items(&self) -> impl Iterator<Item = &rustdoc_types::Item> {
211        self.item_ids().map(|id| &self.krate.index[id])
212    }
213
214    pub fn parent(&self) -> Option<ModuleItem<'a>> {
215        self.krate
216            .all_modules()
217            .find(|module| module.module.items.contains(&self.item.id))
218    }
219
220    pub fn is_crate(&self) -> bool {
221        self.module.is_crate
222    }
223
224    pub fn is_stripped(&self) -> bool {
225        self.module.is_stripped
226    }
227}
228
229impl_items!(ModuleItem<'a>);
230
231#[derive(Debug, Copy, Clone, PartialEq, Eq)]
232pub struct FunctionItem<'a> {
233    krate: &'a Crate,
234    item: &'a rustdoc_types::Item,
235    func: &'a rustdoc_types::Function,
236}
237
238impl<'a> CrateItem<'a> for FunctionItem<'a> {
239    type Inner = rustdoc_types::Function;
240    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
241        match inner {
242            rustdoc_types::ItemEnum::Function(func) => Some(func),
243            _ => None,
244        }
245    }
246    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, func: &'a Self::Inner) -> Self {
247        Self { krate, item, func }
248    }
249    fn item(&self) -> &'a rustdoc_types::Item {
250        self.item
251    }
252    fn inner(&self) -> &'a Self::Inner {
253        self.func
254    }
255    fn krate(&self) -> &'a Crate {
256        self.krate
257    }
258}
259
260impl HasName for FunctionItem<'_> {
261    fn name(&self) -> &str {
262        self.item.name.as_ref().unwrap()
263    }
264}
265
266impl<'a> FunctionItem<'a> {
267    pub fn name(&self) -> &str {
268        self.item.name.as_ref().unwrap()
269    }
270
271    pub fn is_method(&self) -> bool {
272        self.func
273            .sig
274            .inputs
275            .first()
276            .is_some_and(|(name, _)| name == "self")
277    }
278
279    pub fn is_associated(&self) -> bool {
280        self.krate
281            .all_impls()
282            .any(|imp| imp.item_ids().any(|id| id == &self.item.id))
283    }
284
285    pub fn associated_impl(&self) -> Option<ImplItem<'a>> {
286        self.krate
287            .all_impls()
288            .find(|imp| imp.item_ids().any(|id| id == &self.item.id))
289    }
290
291    pub fn inputs(&self) -> impl Iterator<Item = &(String, Type)> {
292        self.func.sig.inputs.iter()
293    }
294
295    pub fn output(&self) -> Option<&Type> {
296        self.func.sig.output.as_ref()
297    }
298
299    pub fn sig(&self) -> &rustdoc_types::FunctionSignature {
300        &self.func.sig
301    }
302
303    pub fn generics(&self) -> &rustdoc_types::Generics {
304        &self.func.generics
305    }
306
307    pub fn header(&self) -> &rustdoc_types::FunctionHeader {
308        &self.func.header
309    }
310
311    pub fn has_body(&self) -> bool {
312        self.func.has_body
313    }
314}
315
316#[derive(Debug, Copy, Clone, PartialEq, Eq)]
317pub struct ConstantItem<'a> {
318    krate: &'a Crate,
319    item: &'a rustdoc_types::Item,
320    constant_item: &'a rustdoc_types::ItemEnum,
321}
322
323impl<'a> CrateItem<'a> for ConstantItem<'a> {
324    type Inner = rustdoc_types::ItemEnum;
325    fn downcast(inner: &'a rustdoc_types::ItemEnum) -> Option<&'a Self::Inner> {
326        match inner {
327            rustdoc_types::ItemEnum::Constant { .. } => Some(inner),
328            _ => None,
329        }
330    }
331    fn new(
332        krate: &'a Crate,
333        item: &'a rustdoc_types::Item,
334        constant_item: &'a Self::Inner,
335    ) -> Self {
336        Self {
337            krate,
338            item,
339            constant_item,
340        }
341    }
342    fn item(&self) -> &'a rustdoc_types::Item {
343        self.item
344    }
345    fn inner(&self) -> &'a Self::Inner {
346        self.constant_item
347    }
348    fn krate(&self) -> &'a Crate {
349        self.krate
350    }
351}
352
353impl HasName for ConstantItem<'_> {
354    fn name(&self) -> &str {
355        self.item.name.as_ref().unwrap()
356    }
357}
358
359impl HasType for ConstantItem<'_> {
360    fn type_(&self) -> &Type {
361        let rustdoc_types::ItemEnum::Constant { type_, .. } = &self.constant_item else {
362            unreachable!();
363        };
364        type_
365    }
366}
367
368impl<'a> ConstantItem<'a> {
369    pub fn name(&self) -> &str {
370        self.item.name.as_ref().unwrap()
371    }
372
373    pub fn type_(&self) -> &Type {
374        let rustdoc_types::ItemEnum::Constant { type_, .. } = &self.constant_item else {
375            unreachable!();
376        };
377        type_
378    }
379
380    pub fn expr(&self) -> &str {
381        let rustdoc_types::ItemEnum::Constant { const_, .. } = &self.constant_item else {
382            unreachable!();
383        };
384        &const_.expr
385    }
386
387    pub fn value(&self) -> Option<&str> {
388        let rustdoc_types::ItemEnum::Constant { const_, .. } = &self.constant_item else {
389            unreachable!();
390        };
391        const_.value.as_deref()
392    }
393}
394
395#[derive(Debug, Copy, Clone, PartialEq, Eq)]
396pub struct StaticItem<'a> {
397    krate: &'a Crate,
398    item: &'a rustdoc_types::Item,
399    static_: &'a rustdoc_types::Static,
400}
401
402impl<'a> CrateItem<'a> for StaticItem<'a> {
403    type Inner = rustdoc_types::Static;
404    fn downcast(inner: &'a rustdoc_types::ItemEnum) -> Option<&'a Self::Inner> {
405        match inner {
406            rustdoc_types::ItemEnum::Static(static_) => Some(static_),
407            _ => None,
408        }
409    }
410    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, static_: &'a Self::Inner) -> Self {
411        Self {
412            krate,
413            item,
414            static_,
415        }
416    }
417    fn item(&self) -> &'a rustdoc_types::Item {
418        self.item
419    }
420    fn inner(&self) -> &'a Self::Inner {
421        self.static_
422    }
423    fn krate(&self) -> &'a Crate {
424        self.krate
425    }
426}
427
428impl HasName for StaticItem<'_> {
429    fn name(&self) -> &str {
430        self.item.name.as_ref().unwrap()
431    }
432}
433
434impl HasType for StaticItem<'_> {
435    fn type_(&self) -> &Type {
436        &self.static_.type_
437    }
438}
439
440impl<'a> StaticItem<'a> {
441    pub fn name(&self) -> &str {
442        self.item.name.as_ref().unwrap()
443    }
444
445    pub fn type_(&self) -> &Type {
446        &self.static_.type_
447    }
448
449    pub fn expr(&self) -> &str {
450        &self.static_.expr
451    }
452
453    pub fn is_mutable(&self) -> bool {
454        self.static_.is_mutable
455    }
456
457    pub fn is_unsafe(&self) -> bool {
458        self.static_.is_unsafe
459    }
460}
461
462#[derive(Debug, Copy, Clone, PartialEq, Eq)]
463pub struct StructItem<'a> {
464    krate: &'a Crate,
465    item: &'a rustdoc_types::Item,
466    struct_: &'a rustdoc_types::Struct,
467}
468
469impl<'a> CrateItem<'a> for StructItem<'a> {
470    type Inner = rustdoc_types::Struct;
471    fn downcast(inner: &'a rustdoc_types::ItemEnum) -> Option<&'a Self::Inner> {
472        match inner {
473            rustdoc_types::ItemEnum::Struct(struct_) => Some(struct_),
474            _ => None,
475        }
476    }
477    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, struct_: &'a Self::Inner) -> Self {
478        Self {
479            krate,
480            item,
481            struct_,
482        }
483    }
484    fn item(&self) -> &'a rustdoc_types::Item {
485        self.item
486    }
487    fn inner(&self) -> &'a Self::Inner {
488        self.struct_
489    }
490    fn krate(&self) -> &'a Crate {
491        self.krate
492    }
493}
494
495impl HasName for StructItem<'_> {
496    fn name(&self) -> &str {
497        self.item.name.as_ref().unwrap()
498    }
499}
500
501impl<'a> StructItem<'a> {
502    pub fn name(&self) -> &str {
503        self.item.name.as_ref().unwrap()
504    }
505
506    pub fn field_ids(&self) -> Option<impl Iterator<Item = &Id>> {
507        match &self.struct_.kind {
508            rustdoc_types::StructKind::Unit => None,
509            rustdoc_types::StructKind::Tuple(_) => None,
510            rustdoc_types::StructKind::Plain { fields, .. } => Some(fields.iter()),
511        }
512    }
513
514    pub fn fields(&self) -> Option<impl Iterator<Item = FieldItem<'_>>> {
515        self.field_ids().map(|ids| {
516            ids.map(|id| {
517                let item = &self.krate.index[id];
518                let rustdoc_types::ItemEnum::StructField(field) = &item.inner else {
519                    panic!("expected struct field, got {:?}", item.inner);
520                };
521                FieldItem {
522                    krate: self.krate,
523                    item,
524                    field,
525                }
526            })
527        })
528    }
529
530    pub fn impl_ids(&self) -> impl Iterator<Item = &Id> {
531        self.struct_.impls.iter()
532    }
533
534    pub fn impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
535        self.impl_ids().map(|id| {
536            let item = &self.krate.index[id];
537            let rustdoc_types::ItemEnum::Impl(imp) = &item.inner else {
538                panic!("expected impl, got {:?}", item.inner);
539            };
540            ImplItem {
541                krate: self.krate,
542                item,
543                impl_: imp,
544            }
545        })
546    }
547
548    /// Iterate over struct impls that are trait impls (`impl <Trait> for <Struct> { ... }`).
549    /// These may include auto/blanket impls.
550    pub fn trait_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
551        self.impls().filter(|imp| imp.trait_().is_some())
552    }
553
554    /// Iterate over struct blanket impls (`impl<T: ...> <Trait> for <Struct<T>> { ... }`).
555    pub fn blanket_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
556        self.trait_impls()
557            .filter(|imp| imp.impl_.blanket_impl.is_some())
558    }
559
560    /// Iterate over struct non-blanket impls (`impl <Trait> for <Struct> { ... }`).
561    pub fn non_blanket_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
562        self.trait_impls()
563            .filter(|imp| imp.impl_.blanket_impl.is_none())
564    }
565
566    /// Iterator over struct impls that are not trait impls.
567    pub fn associated_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
568        self.impls().filter(|imp| imp.trait_().is_none())
569    }
570
571    pub fn kind(&self) -> &rustdoc_types::StructKind {
572        &self.struct_.kind
573    }
574
575    pub fn generics(&self) -> &rustdoc_types::Generics {
576        &self.struct_.generics
577    }
578}
579
580#[derive(Debug, Copy, Clone, PartialEq, Eq)]
581pub struct FieldItem<'a> {
582    krate: &'a Crate,
583    item: &'a rustdoc_types::Item,
584    field: &'a rustdoc_types::Type,
585}
586
587impl<'a> CrateItem<'a> for FieldItem<'a> {
588    type Inner = rustdoc_types::Type;
589    fn downcast(inner: &'a rustdoc_types::ItemEnum) -> Option<&'a Self::Inner> {
590        match inner {
591            rustdoc_types::ItemEnum::StructField(field) => Some(field),
592            _ => None,
593        }
594    }
595    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, field: &'a Self::Inner) -> Self {
596        Self { krate, item, field }
597    }
598    fn item(&self) -> &'a rustdoc_types::Item {
599        self.item
600    }
601    fn inner(&self) -> &'a Self::Inner {
602        self.field
603    }
604    fn krate(&self) -> &'a Crate {
605        self.krate
606    }
607}
608
609impl<'a> HasType for FieldItem<'a> {
610    fn type_(&self) -> &Type {
611        self.field
612    }
613}
614
615impl HasName for FieldItem<'_> {
616    fn name(&self) -> &str {
617        self.item.name.as_ref().unwrap()
618    }
619}
620
621impl<'a> FieldItem<'a> {
622    pub fn name(&self) -> &str {
623        self.item.name.as_ref().unwrap()
624    }
625
626    pub fn type_(&self) -> &Type {
627        self.field
628    }
629}
630
631#[derive(Debug, Copy, Clone, PartialEq, Eq)]
632pub struct TraitItem<'a> {
633    krate: &'a Crate,
634    item: &'a rustdoc_types::Item,
635    trait_: &'a rustdoc_types::Trait,
636}
637
638impl<'a> CrateItem<'a> for TraitItem<'a> {
639    type Inner = rustdoc_types::Trait;
640    fn downcast(inner: &'a rustdoc_types::ItemEnum) -> Option<&'a Self::Inner> {
641        match inner {
642            rustdoc_types::ItemEnum::Trait(trait_) => Some(trait_),
643            _ => None,
644        }
645    }
646    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, trait_: &'a Self::Inner) -> Self {
647        Self {
648            krate,
649            item,
650            trait_,
651        }
652    }
653    fn item(&self) -> &'a rustdoc_types::Item {
654        self.item
655    }
656    fn inner(&self) -> &'a Self::Inner {
657        self.trait_
658    }
659    fn krate(&self) -> &'a Crate {
660        self.krate
661    }
662}
663
664impl HasName for TraitItem<'_> {
665    fn name(&self) -> &str {
666        self.item.name.as_ref().unwrap()
667    }
668}
669
670impl<'a> TraitItem<'a> {
671    pub fn name(&self) -> &str {
672        self.item.name.as_ref().unwrap()
673    }
674
675    pub fn item_ids(&self) -> impl Iterator<Item = &Id> {
676        self.trait_.items.iter()
677    }
678
679    pub fn items(&self) -> impl Iterator<Item = &rustdoc_types::Item> {
680        self.item_ids().map(|id| &self.krate.index[id])
681    }
682
683    pub fn impl_ids(&self) -> impl Iterator<Item = &Id> {
684        self.trait_.implementations.iter()
685    }
686
687    pub fn impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
688        self.impl_ids().map(|id| {
689            let item = &self.krate.index[id];
690            let rustdoc_types::ItemEnum::Impl(imp) = &item.inner else {
691                panic!("expected impl, got {:?}", item.inner);
692            };
693            ImplItem {
694                krate: self.krate,
695                item,
696                impl_: imp,
697            }
698        })
699    }
700
701    pub fn generics(&self) -> &rustdoc_types::Generics {
702        &self.trait_.generics
703    }
704
705    pub fn bounds(&self) -> &[rustdoc_types::GenericBound] {
706        &self.trait_.bounds
707    }
708
709    pub fn is_auto(&self) -> bool {
710        self.trait_.is_auto
711    }
712
713    pub fn is_unsafe(&self) -> bool {
714        self.trait_.is_unsafe
715    }
716
717    pub fn is_dyn_compatible(&self) -> bool {
718        self.trait_.is_dyn_compatible
719    }
720}
721
722#[derive(Debug, Copy, Clone, PartialEq, Eq)]
723pub struct EnumItem<'a> {
724    krate: &'a Crate,
725    item: &'a rustdoc_types::Item,
726    enum_: &'a rustdoc_types::Enum,
727}
728
729impl<'a> CrateItem<'a> for EnumItem<'a> {
730    type Inner = rustdoc_types::Enum;
731    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
732        match inner {
733            rustdoc_types::ItemEnum::Enum(enum_) => Some(enum_),
734            _ => None,
735        }
736    }
737    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, enum_: &'a Self::Inner) -> Self {
738        Self { krate, item, enum_ }
739    }
740    fn item(&self) -> &'a rustdoc_types::Item {
741        self.item
742    }
743    fn inner(&self) -> &'a Self::Inner {
744        self.enum_
745    }
746    fn krate(&self) -> &'a Crate {
747        self.krate
748    }
749}
750
751impl HasName for EnumItem<'_> {
752    fn name(&self) -> &str {
753        self.item.name.as_ref().unwrap()
754    }
755}
756
757impl<'a> EnumItem<'a> {
758    pub fn name(&self) -> &str {
759        self.item.name.as_ref().unwrap()
760    }
761
762    pub fn variant_ids(&self) -> impl Iterator<Item = &Id> {
763        self.enum_.variants.iter()
764    }
765
766    pub fn variants(&self) -> impl Iterator<Item = VariantItem<'_>> {
767        self.variant_ids().map(|id| {
768            let item = &self.krate.index[id];
769            let rustdoc_types::ItemEnum::Variant(variant) = &item.inner else {
770                panic!("expected variant, got {:?}", item.inner);
771            };
772            VariantItem {
773                krate: self.krate,
774                item,
775                variant,
776            }
777        })
778    }
779
780    pub fn impl_ids(&self) -> impl Iterator<Item = &Id> {
781        self.enum_.impls.iter()
782    }
783
784    pub fn impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
785        self.impl_ids().map(|id| {
786            let item = &self.krate.index[id];
787            let rustdoc_types::ItemEnum::Impl(imp) = &item.inner else {
788                panic!("expected impl, got {:?}", item.inner);
789            };
790            ImplItem {
791                krate: self.krate,
792                item,
793                impl_: imp,
794            }
795        })
796    }
797
798    pub fn trait_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
799        self.impls().filter(|imp| imp.trait_().is_some())
800    }
801
802    pub fn blanket_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
803        self.trait_impls()
804            .filter(|imp| imp.impl_.blanket_impl.is_some())
805    }
806
807    pub fn non_blanket_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
808        self.trait_impls()
809            .filter(|imp| imp.impl_.blanket_impl.is_none())
810    }
811
812    /// Iterator over struct impls that are not trait impls.
813    pub fn associated_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
814        self.impls().filter(|imp| imp.trait_().is_none())
815    }
816
817    pub fn generics(&self) -> &rustdoc_types::Generics {
818        &self.enum_.generics
819    }
820
821    pub fn has_stripped_variants(&self) -> bool {
822        self.enum_.has_stripped_variants
823    }
824}
825
826#[derive(Debug, Copy, Clone, PartialEq, Eq)]
827pub struct VariantItem<'a> {
828    krate: &'a Crate,
829    item: &'a rustdoc_types::Item,
830    variant: &'a rustdoc_types::Variant,
831}
832
833impl<'a> CrateItem<'a> for VariantItem<'a> {
834    type Inner = rustdoc_types::Variant;
835    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
836        match inner {
837            rustdoc_types::ItemEnum::Variant(variant) => Some(variant),
838            _ => None,
839        }
840    }
841    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, variant: &'a Self::Inner) -> Self {
842        Self {
843            krate,
844            item,
845            variant,
846        }
847    }
848    fn item(&self) -> &'a rustdoc_types::Item {
849        self.item
850    }
851    fn inner(&self) -> &'a Self::Inner {
852        self.variant
853    }
854    fn krate(&self) -> &'a Crate {
855        self.krate
856    }
857}
858
859impl HasName for VariantItem<'_> {
860    fn name(&self) -> &str {
861        self.item.name.as_ref().unwrap()
862    }
863}
864
865impl<'a> VariantItem<'a> {
866    pub fn name(&self) -> &str {
867        self.item.name.as_ref().unwrap()
868    }
869
870    pub fn kind(&self) -> &rustdoc_types::VariantKind {
871        &self.variant.kind
872    }
873
874    pub fn discriminant(&self) -> Option<&rustdoc_types::Discriminant> {
875        self.variant.discriminant.as_ref()
876    }
877}
878
879#[derive(Debug, Copy, Clone, PartialEq, Eq)]
880pub struct UnionItem<'a> {
881    krate: &'a Crate,
882    item: &'a rustdoc_types::Item,
883    union: &'a rustdoc_types::Union,
884}
885
886impl<'a> CrateItem<'a> for UnionItem<'a> {
887    type Inner = rustdoc_types::Union;
888    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
889        match inner {
890            rustdoc_types::ItemEnum::Union(union) => Some(union),
891            _ => None,
892        }
893    }
894    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, union: &'a Self::Inner) -> Self {
895        Self { krate, item, union }
896    }
897    fn item(&self) -> &'a rustdoc_types::Item {
898        self.item
899    }
900    fn inner(&self) -> &'a Self::Inner {
901        self.union
902    }
903    fn krate(&self) -> &'a Crate {
904        self.krate
905    }
906}
907
908impl HasName for UnionItem<'_> {
909    fn name(&self) -> &str {
910        self.item.name.as_ref().unwrap()
911    }
912}
913
914impl<'a> UnionItem<'a> {
915    pub fn name(&self) -> &str {
916        self.item.name.as_ref().unwrap()
917    }
918
919    pub fn field_ids(&self) -> impl Iterator<Item = &Id> {
920        self.union.fields.iter()
921    }
922
923    pub fn fields(&self) -> impl Iterator<Item = FieldItem<'_>> {
924        self.field_ids().map(|id| {
925            let item = &self.krate.index[id];
926            let rustdoc_types::ItemEnum::StructField(field) = &item.inner else {
927                panic!("expected struct field, got {:?}", item.inner);
928            };
929            FieldItem {
930                krate: self.krate,
931                item,
932                field,
933            }
934        })
935    }
936
937    pub fn impl_ids(&self) -> impl Iterator<Item = &Id> {
938        self.union.impls.iter()
939    }
940
941    pub fn impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
942        self.impl_ids().map(|id| {
943            let item = &self.krate.index[id];
944            let rustdoc_types::ItemEnum::Impl(imp) = &item.inner else {
945                panic!("expected impl, got {:?}", item.inner);
946            };
947            ImplItem {
948                krate: self.krate,
949                item,
950                impl_: imp,
951            }
952        })
953    }
954
955    pub fn trait_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
956        self.impls().filter(|imp| imp.trait_().is_some())
957    }
958
959    pub fn blanket_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
960        self.trait_impls()
961            .filter(|imp| imp.impl_.blanket_impl.is_some())
962    }
963
964    pub fn non_blanket_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
965        self.trait_impls()
966            .filter(|imp| imp.impl_.blanket_impl.is_none())
967    }
968
969    /// Iterator over struct impls that are not trait impls.
970    pub fn associated_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
971        self.impls().filter(|imp| imp.trait_().is_none())
972    }
973
974    pub fn generics(&self) -> &rustdoc_types::Generics {
975        &self.union.generics
976    }
977
978    pub fn has_stripped_fields(&self) -> bool {
979        self.union.has_stripped_fields
980    }
981}
982
983#[derive(Debug, Copy, Clone, PartialEq, Eq)]
984pub struct TypeAliasItem<'a> {
985    krate: &'a Crate,
986    item: &'a rustdoc_types::Item,
987    type_alias: &'a rustdoc_types::TypeAlias,
988}
989
990impl<'a> CrateItem<'a> for TypeAliasItem<'a> {
991    type Inner = rustdoc_types::TypeAlias;
992    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
993        match inner {
994            rustdoc_types::ItemEnum::TypeAlias(type_alias) => Some(type_alias),
995            _ => None,
996        }
997    }
998    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, type_alias: &'a Self::Inner) -> Self {
999        Self {
1000            krate,
1001            item,
1002            type_alias,
1003        }
1004    }
1005    fn item(&self) -> &'a rustdoc_types::Item {
1006        self.item
1007    }
1008    fn inner(&self) -> &'a Self::Inner {
1009        self.type_alias
1010    }
1011    fn krate(&self) -> &'a Crate {
1012        self.krate
1013    }
1014}
1015
1016impl HasName for TypeAliasItem<'_> {
1017    fn name(&self) -> &str {
1018        self.item.name.as_ref().unwrap()
1019    }
1020}
1021
1022impl<'a> TypeAliasItem<'a> {
1023    pub fn name(&self) -> &str {
1024        self.item.name.as_ref().unwrap()
1025    }
1026
1027    pub fn type_(&self) -> &Type {
1028        &self.type_alias.type_
1029    }
1030
1031    pub fn generics(&self) -> &rustdoc_types::Generics {
1032        &self.type_alias.generics
1033    }
1034}
1035
1036#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1037pub struct TraitAliasItem<'a> {
1038    krate: &'a Crate,
1039    item: &'a rustdoc_types::Item,
1040    trait_alias: &'a rustdoc_types::TraitAlias,
1041}
1042
1043impl<'a> CrateItem<'a> for TraitAliasItem<'a> {
1044    type Inner = rustdoc_types::TraitAlias;
1045    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
1046        match inner {
1047            rustdoc_types::ItemEnum::TraitAlias(trait_alias) => Some(trait_alias),
1048            _ => None,
1049        }
1050    }
1051    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, trait_alias: &'a Self::Inner) -> Self {
1052        Self {
1053            krate,
1054            item,
1055            trait_alias,
1056        }
1057    }
1058    fn item(&self) -> &'a rustdoc_types::Item {
1059        self.item
1060    }
1061    fn inner(&self) -> &'a Self::Inner {
1062        self.trait_alias
1063    }
1064    fn krate(&self) -> &'a Crate {
1065        self.krate
1066    }
1067}
1068
1069impl HasName for TraitAliasItem<'_> {
1070    fn name(&self) -> &str {
1071        self.item.name.as_ref().unwrap()
1072    }
1073}
1074
1075impl<'a> TraitAliasItem<'a> {
1076    pub fn name(&self) -> &str {
1077        self.item.name.as_ref().unwrap()
1078    }
1079
1080    pub fn generics(&self) -> &rustdoc_types::Generics {
1081        &self.trait_alias.generics
1082    }
1083
1084    pub fn params(&self) -> &[rustdoc_types::GenericBound] {
1085        &self.trait_alias.params
1086    }
1087}
1088
1089#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1090pub struct ImplItem<'a> {
1091    krate: &'a Crate,
1092    item: &'a rustdoc_types::Item,
1093    impl_: &'a rustdoc_types::Impl,
1094}
1095
1096impl<'a> CrateItem<'a> for ImplItem<'a> {
1097    type Inner = rustdoc_types::Impl;
1098    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
1099        match inner {
1100            rustdoc_types::ItemEnum::Impl(impl_) => Some(impl_),
1101            _ => None,
1102        }
1103    }
1104    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, impl_: &'a Self::Inner) -> Self {
1105        Self { krate, item, impl_ }
1106    }
1107    fn item(&self) -> &'a rustdoc_types::Item {
1108        self.item
1109    }
1110    fn inner(&self) -> &'a Self::Inner {
1111        self.impl_
1112    }
1113    fn krate(&self) -> &'a Crate {
1114        self.krate
1115    }
1116}
1117
1118impl<'a> ImplItem<'a> {
1119    pub fn id(&self) -> &Id {
1120        &self.item.id
1121    }
1122
1123    pub fn item_ids(&self) -> impl Iterator<Item = &Id> {
1124        self.impl_.items.iter()
1125    }
1126
1127    pub fn items(&self) -> impl Iterator<Item = &rustdoc_types::Item> {
1128        self.item_ids().map(|id| &self.krate.index[id])
1129    }
1130
1131    pub fn trait_(&self) -> Option<&rustdoc_types::Path> {
1132        self.impl_.trait_.as_ref()
1133    }
1134
1135    pub fn for_(&self) -> &rustdoc_types::Type {
1136        &self.impl_.for_
1137    }
1138
1139    pub fn is_unsafe(&self) -> bool {
1140        self.impl_.is_unsafe
1141    }
1142
1143    pub fn generics(&self) -> &rustdoc_types::Generics {
1144        &self.impl_.generics
1145    }
1146
1147    pub fn provided_trait_methods(&self) -> &[String] {
1148        &self.impl_.provided_trait_methods
1149    }
1150}
1151
1152impl_items!(ImplItem<'a>);
1153
1154#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1155pub struct MacroItem<'a> {
1156    krate: &'a Crate,
1157    item: &'a rustdoc_types::Item,
1158    macro_: &'a String,
1159}
1160
1161impl<'a> CrateItem<'a> for MacroItem<'a> {
1162    type Inner = String;
1163    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
1164        match inner {
1165            rustdoc_types::ItemEnum::Macro(macro_) => Some(macro_),
1166            _ => None,
1167        }
1168    }
1169    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, macro_: &'a Self::Inner) -> Self {
1170        Self {
1171            krate,
1172            item,
1173            macro_,
1174        }
1175    }
1176    fn item(&self) -> &'a rustdoc_types::Item {
1177        self.item
1178    }
1179    fn inner(&self) -> &'a Self::Inner {
1180        self.macro_
1181    }
1182    fn krate(&self) -> &'a Crate {
1183        self.krate
1184    }
1185}
1186
1187impl HasName for MacroItem<'_> {
1188    fn name(&self) -> &str {
1189        self.item.name.as_ref().unwrap()
1190    }
1191}
1192
1193impl<'a> MacroItem<'a> {
1194    pub fn name(&self) -> &str {
1195        self.item.name.as_ref().unwrap()
1196    }
1197
1198    pub fn macro_(&self) -> &str {
1199        self.macro_
1200    }
1201}
1202
1203pub struct UseItem<'a> {
1204    krate: &'a Crate,
1205    item: &'a rustdoc_types::Item,
1206    import: &'a rustdoc_types::Use,
1207}
1208
1209impl<'a> CrateItem<'a> for UseItem<'a> {
1210    type Inner = rustdoc_types::Use;
1211    fn downcast(inner: &rustdoc_types::ItemEnum) -> Option<&Self::Inner> {
1212        match inner {
1213            rustdoc_types::ItemEnum::Use(import) => Some(import),
1214            _ => None,
1215        }
1216    }
1217    fn new(krate: &'a Crate, item: &'a rustdoc_types::Item, import: &'a Self::Inner) -> Self {
1218        Self {
1219            krate,
1220            item,
1221            import,
1222        }
1223    }
1224    fn item(&self) -> &'a rustdoc_types::Item {
1225        self.item
1226    }
1227    fn inner(&self) -> &'a Self::Inner {
1228        self.import
1229    }
1230    fn krate(&self) -> &'a Crate {
1231        self.krate
1232    }
1233}
1234
1235impl UseItem<'_> {
1236    /// e.g.
1237    ///
1238    /// `pub use foo::bar;` -> as_name == "bar", source == "foo::bar", is_glob == false
1239    ///
1240    /// `pub use foo::*;` -> as_name == "foo", source == "foo", is_glob == true
1241    ///
1242    /// `pub use foo::bar as baz;` -> as_name == "baz", source == "foo::bar", is_glob == false
1243    pub fn as_name(&self) -> &str {
1244        &self.import.name
1245    }
1246
1247    /// e.g.
1248    ///
1249    /// `pub use foo::bar;` -> as_name == "bar", source == "foo::bar", is_glob == false
1250    ///
1251    /// `pub use foo::*;` -> as_name == "foo", source == "foo", is_glob == true
1252    ///
1253    /// `pub use foo::bar as baz;` -> as_name == "baz", source == "foo::bar", is_glob == false
1254    pub fn source(&self) -> &str {
1255        &self.import.source
1256    }
1257
1258    pub fn is_glob(&self) -> bool {
1259        self.import.is_glob
1260    }
1261}
1262
1263#[derive(Clone, PartialEq, Eq)]
1264pub struct Crate(rustdoc_types::Crate);
1265
1266impl std::fmt::Debug for Crate {
1267    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1268        f.debug_struct("Crate")
1269            .field("root", &self.root)
1270            .field("crate_version", &self.crate_version)
1271            .field("...", &"...")
1272            .finish()
1273    }
1274}
1275
1276impl Deref for Crate {
1277    type Target = rustdoc_types::Crate;
1278
1279    fn deref(&self) -> &Self::Target {
1280        &self.0
1281    }
1282}
1283
1284impl Crate {
1285    /// All items in the crate, including external items referenced locally.
1286    pub fn all_items(&self) -> impl Iterator<Item = &rustdoc_types::Item> {
1287        self.0.index.values()
1288    }
1289
1290    /// Items in the crate, excluding external items referenced locally.
1291    pub fn items(&self) -> impl Iterator<Item = &rustdoc_types::Item> {
1292        self.all_items().filter(|&item| item.crate_id == 0)
1293    }
1294
1295    pub fn krate(&self) -> &Crate {
1296        self
1297    }
1298
1299    pub fn item_summary(&self) -> impl Iterator<Item = &rustdoc_types::ItemSummary> {
1300        self.0.paths.values()
1301    }
1302
1303    /// Downcast an item to a specific type `T: CrateItem`.
1304    pub fn downcast<'a, T: CrateItem<'a> + 'a>(
1305        &'a self,
1306        item: &'a rustdoc_types::Item,
1307    ) -> Option<T> {
1308        let inner = T::downcast(&item.inner)?;
1309        Some(T::new(self, item, inner))
1310    }
1311
1312    pub fn all_modules(&self) -> impl Iterator<Item = ModuleItem<'_>> {
1313        self.all_items()
1314            .filter_map(|item| self.krate().downcast::<ModuleItem>(item))
1315    }
1316
1317    /// root module included
1318    pub fn modules(&self) -> impl Iterator<Item = ModuleItem<'_>> {
1319        self.all_modules().filter(|module| module.is_crate_item())
1320    }
1321
1322    /// root module not included
1323    ///
1324    /// submodules of submodules not included
1325    pub fn sub_modules(&self) -> impl Iterator<Item = ModuleItem<'_>> {
1326        self.all_modules().filter(|module| {
1327            module
1328                .parent()
1329                .is_some_and(|parent| parent.id() == &self.root)
1330        })
1331    }
1332
1333    /// Enumerates all functions including submodules.
1334    /// methods & associated functions & function declarations included
1335    pub fn all_functions(&self) -> impl Iterator<Item = FunctionItem<'_>> {
1336        self.all_items()
1337            .filter_map(|item| self.krate().downcast::<FunctionItem>(item))
1338    }
1339
1340    /// Enumerates root module functions.
1341    /// methods & associated functions & function declarations not included
1342    pub fn functions(&self) -> impl Iterator<Item = FunctionItem<'_>> {
1343        self.all_functions().filter(|func| {
1344            func.is_root_item() && !func.is_method() && !func.is_associated() && func.func.has_body
1345        })
1346    }
1347
1348    /// Enumerates all constants including submodules
1349    pub fn all_constants(&self) -> impl Iterator<Item = ConstantItem<'_>> {
1350        self.all_items()
1351            .filter_map(|item| self.krate().downcast::<ConstantItem>(item))
1352    }
1353
1354    /// Enumerates root module constants
1355    pub fn constants(&self) -> impl Iterator<Item = ConstantItem<'_>> {
1356        self.all_constants()
1357            .filter(|constant| constant.is_root_item())
1358    }
1359
1360    /// Enumerates all statics including submodules
1361    pub fn all_statics(&self) -> impl Iterator<Item = StaticItem<'_>> {
1362        self.all_items()
1363            .filter_map(|item| self.krate().downcast::<StaticItem>(item))
1364    }
1365
1366    /// Enumerates root module statics
1367    pub fn statics(&self) -> impl Iterator<Item = StaticItem<'_>> {
1368        self.all_statics().filter(|static_| static_.is_root_item())
1369    }
1370
1371    /// Enumerates all structs including submodules
1372    pub fn all_structs(&self) -> impl Iterator<Item = StructItem<'_>> {
1373        self.all_items()
1374            .filter_map(|item| self.krate().downcast::<StructItem>(item))
1375    }
1376
1377    /// Enumerates root module structs
1378    pub fn structs(&self) -> impl Iterator<Item = StructItem<'_>> {
1379        self.all_structs().filter(|struct_| struct_.is_root_item())
1380    }
1381
1382    /// Enumerates all traits including submodules
1383    pub fn all_traits(&self) -> impl Iterator<Item = TraitItem<'_>> {
1384        self.all_items()
1385            .filter_map(|item| self.krate().downcast::<TraitItem>(item))
1386    }
1387
1388    /// Enumerates root module traits
1389    pub fn traits(&self) -> impl Iterator<Item = TraitItem<'_>> {
1390        self.all_traits().filter(|trait_| trait_.is_root_item())
1391    }
1392
1393    /// Enumerates all enums including submodules
1394    pub fn all_enums(&self) -> impl Iterator<Item = EnumItem<'_>> {
1395        self.all_items()
1396            .filter_map(|item| self.krate().downcast::<EnumItem>(item))
1397    }
1398
1399    /// Enumerates root module enums
1400    pub fn enums(&self) -> impl Iterator<Item = EnumItem<'_>> {
1401        self.all_enums().filter(|enum_| enum_.is_root_item())
1402    }
1403
1404    pub fn all_type_aliases(&self) -> impl Iterator<Item = TypeAliasItem<'_>> {
1405        self.all_items()
1406            .filter_map(|item| self.krate().downcast::<TypeAliasItem>(item))
1407    }
1408
1409    pub fn type_aliases(&self) -> impl Iterator<Item = TypeAliasItem<'_>> {
1410        self.all_type_aliases()
1411            .filter(|type_alias| type_alias.is_root_item())
1412    }
1413
1414    pub fn all_trait_aliases(&self) -> impl Iterator<Item = TraitAliasItem<'_>> {
1415        self.all_items()
1416            .filter_map(|item| self.krate().downcast::<TraitAliasItem>(item))
1417    }
1418
1419    pub fn trait_aliases(&self) -> impl Iterator<Item = TraitAliasItem<'_>> {
1420        self.all_trait_aliases()
1421            .filter(|trait_alias| trait_alias.is_root_item())
1422    }
1423
1424    pub fn all_unions(&self) -> impl Iterator<Item = UnionItem<'_>> {
1425        self.all_items()
1426            .filter_map(|item| self.krate().downcast::<UnionItem>(item))
1427    }
1428
1429    pub fn unions(&self) -> impl Iterator<Item = UnionItem<'_>> {
1430        self.all_unions().filter(|union| union.is_root_item())
1431    }
1432
1433    /// Enumerates all referenced impls including submodules, std
1434    pub fn all_impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
1435        self.all_items()
1436            .filter_map(|item| self.krate().downcast::<ImplItem>(item))
1437    }
1438
1439    /// Enumerates root module impls
1440    pub fn impls(&self) -> impl Iterator<Item = ImplItem<'_>> {
1441        self.all_impls().filter(|imp| imp.is_root_item())
1442    }
1443
1444    /// Enumerates all macros including submodules
1445    pub fn all_macros(&self) -> impl Iterator<Item = MacroItem<'_>> {
1446        self.all_items()
1447            .filter_map(|item| self.krate().downcast::<MacroItem>(item))
1448    }
1449
1450    /// Enumerates root module macros
1451    pub fn macros(&self) -> impl Iterator<Item = MacroItem<'_>> {
1452        self.all_macros().filter(|macro_| macro_.is_root_item())
1453    }
1454
1455    /// Enumerates all uses including submodules
1456    pub fn all_uses(&self) -> impl Iterator<Item = UseItem<'_>> {
1457        self.all_items()
1458            .filter_map(|item| self.krate().downcast::<UseItem>(item))
1459    }
1460
1461    /// Enumerates root module uses
1462    pub fn uses(&self) -> impl Iterator<Item = UseItem<'_>> {
1463        self.all_uses().filter(|import| import.is_root_item())
1464    }
1465
1466    /// Get an item by its name.
1467    pub fn get_item(&self, name: &str) -> Option<&rustdoc_types::Item> {
1468        self.items()
1469            .find(|item| item.name.as_ref().is_some_and(|n| n == name))
1470    }
1471
1472    /// Get a constant by its name.
1473    pub fn get_constant(&self, name: &str) -> Option<ConstantItem<'_>> {
1474        self.constants().find(|constant| constant.name() == name)
1475    }
1476
1477    /// Get a function by its name.
1478    pub fn get_function(&self, name: &str) -> Option<FunctionItem<'_>> {
1479        self.functions().find(|func| func.name() == name)
1480    }
1481
1482    /// Get a struct by its name.
1483    pub fn get_struct(&self, name: &str) -> Option<StructItem<'_>> {
1484        self.structs().find(|struct_| struct_.name() == name)
1485    }
1486
1487    /// Get an enum by its name.
1488    pub fn get_enum(&self, name: &str) -> Option<EnumItem<'_>> {
1489        self.enums().find(|enum_| enum_.name() == name)
1490    }
1491
1492    /// Get a trait by its name.
1493    pub fn get_trait(&self, name: &str) -> Option<TraitItem<'_>> {
1494        self.traits().find(|trait_| trait_.name() == name)
1495    }
1496
1497    /// Get a type alias by its name.
1498    pub fn get_type_alias(&self, name: &str) -> Option<TypeAliasItem<'_>> {
1499        self.type_aliases()
1500            .find(|type_alias| type_alias.name() == name)
1501    }
1502
1503    /// Get a trait alias by its name.
1504    pub fn get_trait_alias(&self, name: &str) -> Option<TraitAliasItem<'_>> {
1505        self.trait_aliases()
1506            .find(|trait_alias| trait_alias.name() == name)
1507    }
1508
1509    /// Get a union by its name.
1510    pub fn get_union(&self, name: &str) -> Option<UnionItem<'_>> {
1511        self.unions().find(|union| union.name() == name)
1512    }
1513
1514    /// Get a module by its name.
1515    pub fn get_module(&self, name: &str) -> Option<ModuleItem<'_>> {
1516        self.modules().find(|module| module.name() == name)
1517    }
1518}
1519
1520#[derive(Debug)]
1521pub enum BuildCrateError {
1522    RustdocJson(rustdoc_json::BuildError),
1523    Io(std::io::Error),
1524    Serde(serde_json::Error),
1525}
1526
1527impl std::fmt::Display for BuildCrateError {
1528    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1529        match self {
1530            BuildCrateError::RustdocJson(err) => err.fmt(f),
1531            BuildCrateError::Io(err) => err.fmt(f),
1532            BuildCrateError::Serde(err) => err.fmt(f),
1533        }
1534    }
1535}
1536
1537impl std::error::Error for BuildCrateError {}
1538
1539impl From<rustdoc_json::BuildError> for BuildCrateError {
1540    fn from(err: rustdoc_json::BuildError) -> Self {
1541        Self::RustdocJson(err)
1542    }
1543}
1544
1545impl From<std::io::Error> for BuildCrateError {
1546    fn from(err: std::io::Error) -> Self {
1547        Self::Io(err)
1548    }
1549}
1550
1551impl From<serde_json::Error> for BuildCrateError {
1552    fn from(err: serde_json::Error) -> Self {
1553        Self::Serde(err)
1554    }
1555}
1556
1557#[derive(Default)]
1558pub struct CrateBuilder {
1559    builder: rustdoc_json::Builder,
1560}
1561
1562impl CrateBuilder {
1563    pub fn new() -> Self {
1564        Self {
1565            builder: rustdoc_json::Builder::default(),
1566        }
1567    }
1568
1569    pub fn toolchain(mut self, toolchain: impl Into<String>) -> Self {
1570        self.builder = self.builder.toolchain(toolchain);
1571        self
1572    }
1573
1574    pub fn manifest_path(mut self, manifest_path: impl AsRef<Path>) -> Self {
1575        self.builder = self.builder.manifest_path(manifest_path);
1576        self
1577    }
1578
1579    pub fn all_features(mut self, all_features: bool) -> Self {
1580        self.builder = self.builder.all_features(all_features);
1581        self
1582    }
1583
1584    pub fn package(mut self, package: impl AsRef<str>) -> Self {
1585        self.builder = self.builder.package(package);
1586        self
1587    }
1588
1589    pub fn features(mut self, features: impl IntoIterator<Item = impl AsRef<str>>) -> Self {
1590        self.builder = self.builder.features(features);
1591        self
1592    }
1593
1594    pub fn no_default_features(mut self, no_default_features: bool) -> Self {
1595        self.builder = self.builder.no_default_features(no_default_features);
1596        self
1597    }
1598
1599    pub fn target(mut self, target: String) -> Self {
1600        self.builder = self.builder.target(target);
1601        self
1602    }
1603
1604    pub fn target_dir(mut self, target_dir: impl AsRef<Path>) -> Self {
1605        self.builder = self.builder.target_dir(target_dir);
1606        self
1607    }
1608
1609    pub fn document_private_items(mut self, document_private_items: bool) -> Self {
1610        self.builder = self.builder.document_private_items(document_private_items);
1611        self
1612    }
1613
1614    pub fn quiet(mut self, quiet: bool) -> Self {
1615        self.builder = self.builder.quiet(quiet);
1616        self
1617    }
1618
1619    pub fn silent(mut self, silent: bool) -> Self {
1620        self.builder = self.builder.silent(silent);
1621        self
1622    }
1623
1624    pub fn color(mut self, color: Color) -> Self {
1625        self.builder = self.builder.color(color);
1626        self
1627    }
1628
1629    pub fn color_always(mut self, color_always: bool) -> Self {
1630        if color_always {
1631            self.builder = self.builder.color(Color::Always);
1632        }
1633        self
1634    }
1635
1636    pub fn color_never(mut self, color_never: bool) -> Self {
1637        if color_never {
1638            self.builder = self.builder.color(Color::Never);
1639        }
1640        self
1641    }
1642
1643    pub fn cap_lints(mut self, cap_lints: Option<impl AsRef<str>>) -> Self {
1644        self.builder = self.builder.cap_lints(cap_lints);
1645        self
1646    }
1647
1648    pub fn build(self) -> Result<Crate, BuildCrateError> {
1649        let path = self.builder.build()?;
1650        let krate = serde_json::from_reader(std::fs::File::open(path)?).map(Crate)?;
1651        Ok(krate)
1652    }
1653
1654    pub fn build_with_captured_output(
1655        self,
1656        stdout: impl Write,
1657        stderr: impl Write,
1658    ) -> Result<Crate, BuildCrateError> {
1659        let path = self.builder.build_with_captured_output(stdout, stderr)?;
1660        let krate = serde_json::from_reader(std::fs::File::open(path)?).map(Crate)?;
1661        Ok(krate)
1662    }
1663}