1515
1616use std:: any:: Any ;
1717use std:: cell:: RefCell ;
18- use std:: collections:: hash_map:: Entry ;
1918use std:: ffi:: OsString ;
2019use std:: fs:: File ;
2120use std:: io:: BufWriter ;
@@ -52,7 +51,7 @@ use crate::html::layout;
5251use crate :: html:: render:: search_index:: build_index;
5352use crate :: html:: render:: search_index:: SerializedSearchIndex ;
5453use crate :: html:: render:: sorted_json:: { EscapedJson , SortedJson } ;
55- use crate :: html:: render:: sorted_template:: { self , SortedTemplate } ;
54+ use crate :: html:: render:: sorted_template:: { self , FileFormat , SortedTemplate } ;
5655use crate :: html:: render:: { AssocItemLink , ImplRenderingParameters } ;
5756use crate :: html:: static_files:: { self , suffix_path} ;
5857use crate :: visit:: DocVisitor ;
@@ -78,33 +77,29 @@ pub(crate) fn write_shared(
7877 let crate_name = krate. name ( cx. tcx ( ) ) ;
7978 let crate_name = crate_name. as_str ( ) ; // rand
8079 let crate_name_json = SortedJson :: serialize ( crate_name) ; // "rand"
81- let external_crates = hack_get_external_crate_names ( cx ) ?;
80+ let external_crates = hack_get_external_crate_names ( & cx . dst ) ?;
8281 let info = CrateInfo {
8382 src_files_js : SourcesPart :: get ( cx, & crate_name_json) ?,
84- search_index_js : SearchIndexPart :: get ( cx , index ) ?,
83+ search_index_js : SearchIndexPart :: get ( index , & cx . shared . resource_suffix ) ?,
8584 all_crates : AllCratesPart :: get ( crate_name_json. clone ( ) ) ?,
8685 crates_index : CratesIndexPart :: get ( & crate_name, & external_crates) ?,
8786 trait_impl : TraitAliasPart :: get ( cx, & crate_name_json) ?,
8887 type_impl : TypeAliasPart :: get ( cx, krate, & crate_name_json) ?,
8988 } ;
9089
91- let crates_info = vec ! [ info] ; // we have info from just one crate
90+ let crates = vec ! [ info] ; // we have info from just one crate. rest will found in out dir
9291
9392 write_static_files ( cx, & opt) ?;
9493 let dst = & cx. dst ;
9594 if opt. emit . is_empty ( ) || opt. emit . contains ( & EmitType :: InvocationSpecific ) {
9695 if cx. include_sources {
97- write_rendered_cci :: < SourcesPart , _ > ( SourcesPart :: blank, dst, & crates_info ) ?;
96+ write_rendered_cci :: < SourcesPart , _ > ( SourcesPart :: blank, dst, & crates ) ?;
9897 }
99- write_rendered_cci :: < SearchIndexPart , _ > (
100- SearchIndexPart :: blank,
101- dst,
102- & crates_info,
103- ) ?;
104- write_rendered_cci :: < AllCratesPart , _ > ( AllCratesPart :: blank, dst, & crates_info) ?;
105- }
106- write_rendered_cci :: < TraitAliasPart , _ > ( TraitAliasPart :: blank, dst, & crates_info) ?;
107- write_rendered_cci :: < TypeAliasPart , _ > ( TypeAliasPart :: blank, dst, & crates_info) ?;
98+ write_rendered_cci :: < SearchIndexPart , _ > ( SearchIndexPart :: blank, dst, & crates) ?;
99+ write_rendered_cci :: < AllCratesPart , _ > ( AllCratesPart :: blank, dst, & crates) ?;
100+ }
101+ write_rendered_cci :: < TraitAliasPart , _ > ( TraitAliasPart :: blank, dst, & crates) ?;
102+ write_rendered_cci :: < TypeAliasPart , _ > ( TypeAliasPart :: blank, dst, & crates) ?;
108103 match & opt. index_page {
109104 Some ( index_page) if opt. enable_index_page => {
110105 let mut md_opts = opt. clone ( ) ;
@@ -119,7 +114,7 @@ pub(crate) fn write_shared(
119114 write_rendered_cci :: < CratesIndexPart , _ > (
120115 || CratesIndexPart :: blank ( cx) ,
121116 dst,
122- & crates_info ,
117+ & crates ,
123118 ) ?;
124119 }
125120 _ => { } // they don't want an index page
@@ -189,7 +184,8 @@ fn write_search_desc(
189184 let path = path. join ( filename) ;
190185 let part = SortedJson :: serialize ( & part) ;
191186 let part = format ! ( "searchState.loadedDescShard({encoded_crate_name}, {i}, {part})" ) ;
192- write_create_parents ( & path, part) ?;
187+ create_parents ( & path) ?;
188+ try_err ! ( fs:: write( & path, part) , & path) ;
193189 }
194190 Ok ( ( ) )
195191}
@@ -286,8 +282,11 @@ else if (window.initSearch) window.initSearch(searchIndex);",
286282 )
287283 }
288284
289- fn get ( cx : & Context < ' _ > , search_index : SortedJson ) -> Result < PartsAndLocations < Self > , Error > {
290- let path = suffix_path ( "search-index.js" , & cx. shared . resource_suffix ) ;
285+ fn get (
286+ search_index : SortedJson ,
287+ resource_suffix : & str ,
288+ ) -> Result < PartsAndLocations < Self > , Error > {
289+ let path = suffix_path ( "search-index.js" , resource_suffix) ;
291290 let search_index = EscapedJson :: from ( search_index) ;
292291 Ok ( PartsAndLocations :: with ( path, search_index) )
293292 }
@@ -319,8 +318,8 @@ impl AllCratesPart {
319318///
320319/// This is to match the current behavior of rustdoc, which allows you to get all crates
321320/// on the index page, even if --enable-index-page is only passed to the last crate.
322- fn hack_get_external_crate_names ( cx : & Context < ' _ > ) -> Result < Vec < String > , Error > {
323- let path = cx . dst . join ( "crates.js" ) ;
321+ fn hack_get_external_crate_names ( doc_root : & Path ) -> Result < Vec < String > , Error > {
322+ let path = doc_root . join ( "crates.js" ) ;
324323 let Ok ( content) = fs:: read_to_string ( & path) else {
325324 // they didn't emit invocation specific, so we just say there were no crates
326325 return Ok ( Vec :: default ( ) ) ;
@@ -361,7 +360,7 @@ impl CratesIndexPart {
361360 match SortedTemplate :: magic ( & template, MAGIC ) {
362361 Ok ( template) => template,
363362 Err ( e) => panic ! (
364- "{e}: Object Replacement Character (U+FFFC) should not appear in the --index-page"
363+ "Object Replacement Character (U+FFFC) should not appear in the --index-page: {e} "
365364 ) ,
366365 }
367366 }
@@ -860,27 +859,35 @@ impl Serialize for AliasSerializableImpl {
860859 }
861860}
862861
862+ fn get_path_parts < T : CciPart > (
863+ dst : & Path ,
864+ crates_info : & [ CrateInfo ] ,
865+ ) -> FxHashMap < PathBuf , Vec < String > > {
866+ let mut templates: FxHashMap < PathBuf , Vec < String > > = FxHashMap :: default ( ) ;
867+ crates_info. iter ( ) . map ( |crate_info| crate_info. get :: < T > ( ) . parts . iter ( ) ) . flatten ( ) . for_each (
868+ |( path, part) | {
869+ let path = dst. join ( & path) ;
870+ let part = part. to_string ( ) ;
871+ templates. entry ( path) . or_default ( ) . push ( part) ;
872+ } ,
873+ ) ;
874+ templates
875+ }
876+
863877/// Create all parents
864878fn create_parents ( path : & Path ) -> Result < ( ) , Error > {
865879 let parent = path. parent ( ) . expect ( "should not have an empty path here" ) ;
866880 try_err ! ( fs:: create_dir_all( parent) , parent) ;
867881 Ok ( ( ) )
868882}
869883
870- /// Create parents and then write
871- fn write_create_parents ( path : & Path , content : String ) -> Result < ( ) , Error > {
872- create_parents ( path) ?;
873- try_err ! ( fs:: write( path, content) , path) ;
874- Ok ( ( ) )
875- }
876-
877884/// Returns a blank template unless we could find one to append to
878- fn read_template_or_blank < F , T : CciPart > (
885+ fn read_template_or_blank < F , T : FileFormat > (
879886 mut make_blank : F ,
880887 path : & Path ,
881- ) -> Result < SortedTemplate < T :: FileFormat > , Error >
888+ ) -> Result < SortedTemplate < T > , Error >
882889where
883- F : FnMut ( ) -> SortedTemplate < T :: FileFormat > ,
890+ F : FnMut ( ) -> SortedTemplate < T > ,
884891{
885892 match fs:: read_to_string ( & path) {
886893 Ok ( template) => Ok ( try_err ! ( SortedTemplate :: from_str( & template) , & path) ) ,
@@ -898,31 +905,21 @@ fn write_rendered_cci<T: CciPart, F>(
898905where
899906 F : FnMut ( ) -> SortedTemplate < T :: FileFormat > ,
900907{
901- // read parts from disk
902- let path_parts =
903- crates_info. iter ( ) . map ( |crate_info| crate_info. get :: < T > ( ) . parts . iter ( ) ) . flatten ( ) ;
904- // read previous rendered cci from storage, append to them
905- let mut templates: FxHashMap < PathBuf , SortedTemplate < T :: FileFormat > > = Default :: default ( ) ;
906- for ( path, part) in path_parts {
907- let part = format ! ( "{part}" ) ;
908- let path = dst. join ( & path) ;
909- match templates. entry ( path. clone ( ) ) {
910- Entry :: Vacant ( entry) => {
911- let template = read_template_or_blank :: < _ , T > ( & mut make_blank, & path) ?;
912- let template = entry. insert ( template) ;
913- template. append ( part) ;
914- }
915- Entry :: Occupied ( mut t) => t. get_mut ( ) . append ( part) ,
916- }
917- }
918-
919908 // write the merged cci to disk
920- for ( path, template ) in templates {
909+ for ( path, parts ) in get_path_parts :: < T > ( dst , crates_info ) {
921910 create_parents ( & path) ?;
911+ // read previous rendered cci from storage, append to them
912+ let mut template = read_template_or_blank :: < _ , T :: FileFormat > ( & mut make_blank, & path) ?;
913+ for part in parts {
914+ template. append ( part) ;
915+ }
922916 let file = try_err ! ( File :: create( & path) , & path) ;
923917 let mut file = BufWriter :: new ( file) ;
924918 try_err ! ( write!( file, "{template}" ) , & path) ;
925919 try_err ! ( file. flush( ) , & path) ;
926920 }
927921 Ok ( ( ) )
928922}
923+
924+ #[ cfg( test) ]
925+ mod tests;
0 commit comments