3
3
//! All the static files are included here for centralized access in case anything other than the
4
4
//! HTML rendering code (say, the theme checker) needs to access one of these files.
5
5
6
- use rustc_data_structures:: fx:: FxHasher ;
6
+ use rustc_data_structures:: fx:: { FxHashMap , FxHasher } ;
7
+ use std:: borrow:: Cow ;
7
8
use std:: hash:: Hasher ;
8
9
use std:: path:: { Path , PathBuf } ;
9
10
use std:: { fmt, str} ;
10
11
11
12
pub ( crate ) struct StaticFile {
12
13
pub ( crate ) filename : PathBuf ,
13
- pub ( crate ) bytes : & ' static [ u8 ] ,
14
+ pub ( crate ) bytes : Cow < ' static , [ u8 ] > ,
14
15
}
15
16
16
17
impl 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
+ }
19
36
}
20
37
21
38
pub ( crate ) fn minified ( & self ) -> Vec < u8 > {
22
39
let extension = match self . filename . extension ( ) {
23
40
Some ( e) => e,
24
- None => return self . bytes . to_owned ( ) ,
41
+ None => return self . bytes . to_vec ( ) ,
25
42
} ;
26
43
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 ( )
28
45
} 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 ( )
30
47
} else {
31
- self . bytes . to_owned ( )
48
+ self . bytes . to_vec ( )
32
49
}
33
50
}
34
51
@@ -45,6 +62,26 @@ impl fmt::Display for StaticFile {
45
62
}
46
63
}
47
64
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
+
48
85
/// Insert the provided suffix into a filename just before the extension.
49
86
pub ( crate ) fn suffix_path ( filename : & str , suffix : & str ) -> PathBuf {
50
87
// We use splitn vs Path::extension here because we might get a filename
@@ -74,8 +111,11 @@ macro_rules! static_files {
74
111
$( pub $field: StaticFile , ) +
75
112
}
76
113
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
+ }
79
119
} ) ;
80
120
81
121
pub ( crate ) fn for_each<E >( f: impl Fn ( & StaticFile ) -> Result <( ) , E >) -> Result <( ) , E > {
@@ -90,10 +130,6 @@ macro_rules! static_files {
90
130
}
91
131
92
132
static_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" ,
97
133
main_js => "static/js/main.js" ,
98
134
search_js => "static/js/search.js" ,
99
135
settings_js => "static/js/settings.js" ,
@@ -125,6 +161,12 @@ static_files! {
125
161
source_code_pro_license => "static/fonts/SourceCodePro-LICENSE.txt" ,
126
162
nanum_barun_gothic_regular => "static/fonts/NanumBarunGothic.ttf.woff2" ,
127
163
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" ,
128
170
}
129
171
130
172
pub ( crate ) static SCRAPE_EXAMPLES_HELP_MD : & str = include_str ! ( "static/scrape-examples-help.md" ) ;
0 commit comments