@@ -11,13 +11,15 @@ use guppy::{PackageId, Version};
1111use indexmap:: IndexSet ;
1212use rayon:: iter:: IntoParallelRefIterator ;
1313use rkyv:: collections:: swiss_table:: ArchivedHashMap ;
14+ use rkyv:: hash:: FxHasher64 ;
1415use rkyv:: rancor:: Panic ;
1516use rkyv:: string:: ArchivedString ;
1617use rkyv:: util:: AlignedVec ;
1718use rkyv:: vec:: ArchivedVec ;
1819use rustc_hash:: FxHashMap ;
1920use rustdoc_types:: {
20- ArchivedId , ArchivedItem , ExternalCrate , Item , ItemEnum , ItemKind , ItemSummary , Visibility ,
21+ ArchivedId , ArchivedItem , ArchivedItemSummary , ExternalCrate , Item , ItemEnum , ItemKind ,
22+ ItemSummary , Visibility ,
2123} ;
2224use tracing:: Span ;
2325use tracing_log_error:: log_error;
@@ -989,13 +991,131 @@ pub(crate) struct CrateData {
989991 pub external_crates : FxHashMap < u32 , ExternalCrate > ,
990992 /// A mapping from the id of a type to its fully qualified path.
991993 /// Primarily useful for foreign items that are being re-exported by this crate.
992- #[ allow( clippy:: disallowed_types) ]
993- pub paths : FxHashMap < rustdoc_types:: Id , ItemSummary > ,
994+ pub paths : CrateItemPaths ,
994995 /// The version of the JSON format used by rustdoc.
995996 pub format_version : u32 ,
996997 /// The index of all the items in the crate.
997998 pub index : CrateItemIndex ,
998999}
1000+
1001+ #[ derive( Debug , Clone ) ]
1002+ /// A mapping from the id of a type to its fully qualified path.
1003+ ///
1004+ /// Primarily useful for foreign items that are being re-exported by this crate.
1005+ pub ( crate ) enum CrateItemPaths {
1006+ Eager ( EagerCrateItemPaths ) ,
1007+ Lazy ( LazyCrateItemPaths ) ,
1008+ }
1009+
1010+ impl CrateItemPaths {
1011+ /// Retrieve an item summary from the index given its id.
1012+ pub fn get ( & self , id : & rustdoc_types:: Id ) -> Option < Cow < ' _ , ItemSummary > > {
1013+ match self {
1014+ Self :: Eager ( m) => m. paths . get ( id) . map ( Cow :: Borrowed ) ,
1015+ Self :: Lazy ( m) => {
1016+ let item = m. get_deserialized ( id) ?;
1017+ Some ( Cow :: Owned ( item) )
1018+ }
1019+ }
1020+ }
1021+
1022+ pub fn iter ( & self ) -> impl Iterator < Item = ( rustdoc_types:: Id , ItemSummaryRef < ' _ > ) > {
1023+ match self {
1024+ CrateItemPaths :: Eager ( paths) => CrateItemPathsIter :: Eager ( paths. paths . iter ( ) ) ,
1025+ CrateItemPaths :: Lazy ( paths) => CrateItemPathsIter :: Lazy ( paths. archived ( ) . iter ( ) ) ,
1026+ }
1027+ }
1028+ }
1029+
1030+ pub enum CrateItemPathsIter < ' a > {
1031+ Eager ( std:: collections:: hash_map:: Iter < ' a , rustdoc_types:: Id , ItemSummary > ) ,
1032+ Lazy (
1033+ rkyv:: collections:: swiss_table:: map:: Iter < ' a , ArchivedId , ArchivedItemSummary , FxHasher64 > ,
1034+ ) ,
1035+ }
1036+
1037+ pub enum ItemSummaryRef < ' a > {
1038+ Eager ( & ' a ItemSummary ) ,
1039+ Lazy ( & ' a ArchivedItemSummary ) ,
1040+ }
1041+
1042+ impl < ' a > ItemSummaryRef < ' a > {
1043+ pub fn crate_id ( & self ) -> u32 {
1044+ match self {
1045+ ItemSummaryRef :: Eager ( s) => s. crate_id ,
1046+ ItemSummaryRef :: Lazy ( s) => s. crate_id . to_native ( ) ,
1047+ }
1048+ }
1049+
1050+ pub fn kind ( & self ) -> ItemKind {
1051+ match self {
1052+ ItemSummaryRef :: Eager ( s) => s. kind ,
1053+ ItemSummaryRef :: Lazy ( s) => {
1054+ // Safe to do since the enum is repr(u8)
1055+ rkyv:: deserialize :: < _ , rkyv:: rancor:: Infallible > ( & s. kind ) . unwrap ( )
1056+ }
1057+ }
1058+ }
1059+
1060+ pub fn path ( & self ) -> Cow < ' _ , [ String ] > {
1061+ match self {
1062+ ItemSummaryRef :: Eager ( s) => Cow :: Borrowed ( & s. path ) ,
1063+ ItemSummaryRef :: Lazy ( s) => {
1064+ Cow :: Owned ( s. path . iter ( ) . map ( |s| s. as_str ( ) . to_owned ( ) ) . collect ( ) )
1065+ }
1066+ }
1067+ }
1068+ }
1069+
1070+ impl < ' a > Iterator for CrateItemPathsIter < ' a > {
1071+ type Item = ( rustdoc_types:: Id , ItemSummaryRef < ' a > ) ;
1072+
1073+ fn next ( & mut self ) -> Option < Self :: Item > {
1074+ match self {
1075+ Self :: Eager ( iter) => iter. next ( ) . map ( |( k, v) | ( * k, ItemSummaryRef :: Eager ( v) ) ) ,
1076+ Self :: Lazy ( iter) => iter
1077+ . next ( )
1078+ . map ( |( k, v) | ( rustdoc_types:: Id ( k. 0 . to_native ( ) ) , ItemSummaryRef :: Lazy ( v) ) ) ,
1079+ }
1080+ }
1081+ }
1082+
1083+ #[ derive( Debug , Clone ) ]
1084+ /// See [`CrateItemPaths`] for more information.
1085+ pub ( crate ) struct EagerCrateItemPaths {
1086+ #[ allow( clippy:: disallowed_types) ]
1087+ pub paths : FxHashMap < rustdoc_types:: Id , ItemSummary > ,
1088+ }
1089+
1090+ /// See [`CrateItemPaths`] for more information.
1091+ #[ derive( Debug , Clone ) ]
1092+ pub ( crate ) struct LazyCrateItemPaths {
1093+ pub ( super ) bytes : AlignedVec ,
1094+ }
1095+
1096+ impl LazyCrateItemPaths {
1097+ /// Get zero-copy access to the archived HashMap.
1098+ #[ inline]
1099+ fn archived ( & self ) -> & ArchivedHashMap < ArchivedId , ArchivedItemSummary > {
1100+ // SAFETY: The bytes were serialized by rkyv from a valid HashMap<Id, ItemSummary>.
1101+ // We trust the cache to contain valid data.
1102+ unsafe {
1103+ rkyv:: access_unchecked :: < ArchivedHashMap < ArchivedId , ArchivedItemSummary > > ( & self . bytes )
1104+ }
1105+ }
1106+
1107+ /// Get an item by its ID, returning a reference to the archived summary.
1108+ pub fn get ( & self , id : & rustdoc_types:: Id ) -> Option < & ArchivedItemSummary > {
1109+ self . archived ( ) . get ( & ArchivedId ( id. 0 . into ( ) ) )
1110+ }
1111+
1112+ /// Deserialize a summary by its ID.
1113+ pub fn get_deserialized ( & self , id : & rustdoc_types:: Id ) -> Option < ItemSummary > {
1114+ let archived = self . get ( id) ?;
1115+ Some ( rkyv:: deserialize :: < ItemSummary , Panic > ( archived) . unwrap ( ) )
1116+ }
1117+ }
1118+
9991119#[ derive( Debug , Clone ) ]
10001120/// The index of all the items in the crate.
10011121///
@@ -1107,7 +1227,7 @@ impl Crate {
11071227 index : CrateItemIndex :: Eager ( EagerCrateItemIndex { index : krate. index } ) ,
11081228 external_crates : krate. external_crates ,
11091229 format_version : krate. format_version ,
1110- paths : krate. paths ,
1230+ paths : CrateItemPaths :: Eager ( EagerCrateItemPaths { paths : krate. paths } ) ,
11111231 } ;
11121232 Self :: index ( crate_data, package_id, diagnostics)
11131233 }
@@ -1123,18 +1243,18 @@ impl Crate {
11231243 . iter ( )
11241244 . filter_map ( |( id, summary) | {
11251245 // We only want types, no macros
1126- if matches ! ( summary. kind, ItemKind :: Macro | ItemKind :: ProcDerive ) {
1246+ if matches ! ( summary. kind( ) , ItemKind :: Macro | ItemKind :: ProcDerive ) {
11271247 return None ;
11281248 }
11291249 // We will index local items on our own.
11301250 // We don't get them from `paths` because it may include private items
11311251 // as well, and we don't have a way to figure out if an item is private
11321252 // or not from the summary info.
1133- if summary. crate_id == 0 {
1253+ if summary. crate_id ( ) == 0 {
11341254 return None ;
11351255 }
11361256
1137- Some ( ( summary. path . clone ( ) , id. to_owned ( ) ) )
1257+ Some ( ( summary. path ( ) . into_owned ( ) , id. to_owned ( ) ) )
11381258 } )
11391259 . collect ( ) ;
11401260
@@ -1312,7 +1432,7 @@ impl Crate {
13121432 fn get_summary_by_local_type_id (
13131433 & self ,
13141434 id : & rustdoc_types:: Id ,
1315- ) -> Result < & rustdoc_types:: ItemSummary , anyhow:: Error > {
1435+ ) -> Result < Cow < ' _ , rustdoc_types:: ItemSummary > , anyhow:: Error > {
13161436 self . core . krate . paths . get ( id) . ok_or_else ( || {
13171437 anyhow ! (
13181438 "Failed to look up the type id `{}` in the rustdoc's path index for `{}`. \
0 commit comments