33//! All the static files are included here for centralized access in case anything other than the
44//! HTML rendering code (say, the theme checker) needs to access one of these files.
55
6- use rustc_data_structures:: fx:: FxHasher ;
6+ use rustc_data_structures:: fx:: { FxHashMap , FxHasher } ;
7+ use std:: borrow:: Cow ;
78use std:: hash:: Hasher ;
89use std:: path:: { Path , PathBuf } ;
910use std:: { fmt, str} ;
1011
1112pub ( crate ) struct StaticFile {
1213 pub ( crate ) filename : PathBuf ,
13- pub ( crate ) bytes : & ' static [ u8 ] ,
14+ pub ( crate ) bytes : Cow < ' static , [ u8 ] > ,
1415}
1516
1617impl StaticFile {
17- fn new ( filename : & str , bytes : & ' static [ u8 ] ) -> StaticFile {
18- Self { filename : static_filename ( filename, bytes) , bytes }
18+ fn new (
19+ filename : & str ,
20+ bytes : & ' static [ u8 ] ,
21+ file_map : & mut FxHashMap < String , String > ,
22+ ) -> StaticFile {
23+ // For now, only `rustdoc.css` style file needs this mechanism but it can be extended
24+ // pretty easily by changing this condition.
25+ if filename. ends_with ( "/rustdoc.css" ) {
26+ let bytes = replace_static_files_include ( bytes, file_map) ;
27+ Self { filename : static_filename ( filename, & bytes) , bytes : Cow :: Owned ( bytes) }
28+ } else {
29+ let ret =
30+ Self { filename : static_filename ( filename, bytes) , bytes : Cow :: Borrowed ( bytes) } ;
31+ let filename = Path :: new ( filename) . file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
32+ file_map
33+ . insert ( filename, ret. filename . file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ) ;
34+ ret
35+ }
1936 }
2037
2138 pub ( crate ) fn minified ( & self ) -> Vec < u8 > {
2239 let extension = match self . filename . extension ( ) {
2340 Some ( e) => e,
24- None => return self . bytes . to_owned ( ) ,
41+ None => return self . bytes . to_vec ( ) ,
2542 } ;
2643 if extension == "css" {
27- minifier:: css:: minify ( str:: from_utf8 ( self . bytes ) . unwrap ( ) ) . unwrap ( ) . to_string ( ) . into ( )
44+ minifier:: css:: minify ( str:: from_utf8 ( & self . bytes ) . unwrap ( ) ) . unwrap ( ) . to_string ( ) . into ( )
2845 } else if extension == "js" {
29- minifier:: js:: minify ( str:: from_utf8 ( self . bytes ) . unwrap ( ) ) . to_string ( ) . into ( )
46+ minifier:: js:: minify ( str:: from_utf8 ( & self . bytes ) . unwrap ( ) ) . to_string ( ) . into ( )
3047 } else {
31- self . bytes . to_owned ( )
48+ self . bytes . to_vec ( )
3249 }
3350 }
3451
@@ -45,6 +62,26 @@ impl fmt::Display for StaticFile {
4562 }
4663}
4764
65+ /// This function goes through the CSS content and replaces all content wrapped between:
66+ /// `/* REPLACE {content} */` (where `{content}` is what will be replaced.)
67+ fn replace_static_files_include ( bytes : & [ u8 ] , file_map : & FxHashMap < String , String > ) -> Vec < u8 > {
68+ let bytes = str:: from_utf8 ( bytes) . unwrap ( ) ;
69+ let mut it = bytes. split ( "/* REPLACE " ) ;
70+ let mut content = String :: with_capacity ( bytes. len ( ) ) ;
71+ while let Some ( entry) = it. next ( ) {
72+ if content. is_empty ( ) {
73+ content. push_str ( entry) ;
74+ continue ;
75+ }
76+ let mut parts = entry. splitn ( 2 , " */" ) ;
77+ let file = parts. next ( ) . unwrap ( ) ;
78+ let rest = parts. next ( ) . unwrap ( ) ;
79+ content. push_str ( file_map. get ( file) . unwrap ( ) ) ;
80+ content. push_str ( rest) ;
81+ }
82+ content. into ( )
83+ }
84+
4885/// Insert the provided suffix into a filename just before the extension.
4986pub ( crate ) fn suffix_path ( filename : & str , suffix : & str ) -> PathBuf {
5087 // We use splitn vs Path::extension here because we might get a filename
@@ -74,8 +111,11 @@ macro_rules! static_files {
74111 $( pub $field: StaticFile , ) +
75112 }
76113
77- pub ( crate ) static STATIC_FILES : std:: sync:: LazyLock <StaticFiles > = std:: sync:: LazyLock :: new( || StaticFiles {
78- $( $field: StaticFile :: new( $file_path, include_bytes!( $file_path) ) , ) +
114+ pub ( crate ) static STATIC_FILES : std:: sync:: LazyLock <StaticFiles > = std:: sync:: LazyLock :: new( || {
115+ let mut map = FxHashMap :: default ( ) ;
116+ StaticFiles {
117+ $( $field: StaticFile :: new( $file_path, include_bytes!( $file_path) , & mut map) , ) +
118+ }
79119 } ) ;
80120
81121 pub ( crate ) fn for_each<E >( f: impl Fn ( & StaticFile ) -> Result <( ) , E >) -> Result <( ) , E > {
@@ -90,10 +130,6 @@ macro_rules! static_files {
90130}
91131
92132static_files ! {
93- rustdoc_css => "static/css/rustdoc.css" ,
94- settings_css => "static/css/settings.css" ,
95- noscript_css => "static/css/noscript.css" ,
96- normalize_css => "static/css/normalize.css" ,
97133 main_js => "static/js/main.js" ,
98134 search_js => "static/js/search.js" ,
99135 settings_js => "static/js/settings.js" ,
@@ -125,6 +161,12 @@ static_files! {
125161 source_code_pro_license => "static/fonts/SourceCodePro-LICENSE.txt" ,
126162 nanum_barun_gothic_regular => "static/fonts/NanumBarunGothic.ttf.woff2" ,
127163 nanum_barun_gothic_license => "static/fonts/NanumBarunGothic-LICENSE.txt" ,
164+ // It's important for the CSS files to be the last since we need to replace some of their
165+ // content (the static file names).
166+ rustdoc_css => "static/css/rustdoc.css" ,
167+ settings_css => "static/css/settings.css" ,
168+ noscript_css => "static/css/noscript.css" ,
169+ normalize_css => "static/css/normalize.css" ,
128170}
129171
130172pub ( crate ) static SCRAPE_EXAMPLES_HELP_MD : & str = include_str ! ( "static/scrape-examples-help.md" ) ;
0 commit comments