1
1
use std:: fmt;
2
2
use std:: marker:: PhantomData ;
3
- use rustc_data_structures :: fx :: FxHashSet ;
3
+ use std :: collections :: BTreeSet ;
4
4
use std:: str:: FromStr ;
5
5
6
6
use serde:: { Serialize , Deserialize } ;
@@ -9,20 +9,23 @@ use serde::{Serialize, Deserialize};
9
9
///
10
10
/// Last line of the rendered output is a comment encoding the next insertion point.
11
11
#[ derive( Debug , Clone ) ]
12
- pub ( crate ) struct OffsetTemplate < F > {
12
+ pub ( crate ) struct SortedTemplate < F > {
13
13
format : PhantomData < F > ,
14
14
before : String ,
15
15
after : String ,
16
- contents : FxHashSet < String > ,
16
+ contents : BTreeSet < String > ,
17
17
}
18
18
19
+ /// Written to last line of file to specify the location of each fragment
19
20
#[ derive( Serialize , Deserialize , Debug , Clone ) ]
20
21
struct Offset {
22
+ /// Index of the first byte in the template
21
23
start : usize ,
24
+ /// The length of each fragment in the encoded template, including the separator
22
25
delta : Vec < usize > ,
23
26
}
24
27
25
- impl < F > OffsetTemplate < F > {
28
+ impl < F > SortedTemplate < F > {
26
29
/// Generate this template from arbitary text.
27
30
/// Will insert wherever the substring `magic` can be found.
28
31
/// Errors if it does not appear exactly once.
@@ -40,23 +43,22 @@ impl<F> OffsetTemplate<F> {
40
43
pub ( crate ) fn before_after < S : ToString , T : ToString > ( before : S , after : T ) -> Self {
41
44
let before = before. to_string ( ) ;
42
45
let after = after. to_string ( ) ;
43
- OffsetTemplate { format : PhantomData , before, after, contents : Default :: default ( ) }
46
+ SortedTemplate { format : PhantomData , before, after, contents : Default :: default ( ) }
44
47
}
45
48
}
46
49
47
- impl < F : FileFormat > OffsetTemplate < F > {
48
- /// Adds this text to the next insert point
50
+ impl < F : FileFormat > SortedTemplate < F > {
51
+ /// Adds this text to the template
49
52
pub ( crate ) fn append ( & mut self , insert : String ) {
50
53
self . contents . insert ( insert) ;
51
54
}
52
55
}
53
56
54
- impl < F : FileFormat > fmt:: Display for OffsetTemplate < F > {
57
+ impl < F : FileFormat > fmt:: Display for SortedTemplate < F > {
55
58
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
56
59
let mut delta = Vec :: default ( ) ;
57
60
write ! ( f, "{}" , self . before) ?;
58
- let mut contents: Vec < _ > = self . contents . iter ( ) . collect ( ) ;
59
- contents. sort_unstable ( ) ;
61
+ let contents: Vec < _ > = self . contents . iter ( ) . collect ( ) ;
60
62
let mut sep = "" ;
61
63
for content in contents {
62
64
delta. push ( sep. len ( ) + content. len ( ) ) ;
@@ -74,28 +76,28 @@ fn checked_split_at(s: &str, index: usize) -> Option<(&str, &str)> {
74
76
s. is_char_boundary ( index) . then ( || s. split_at ( index) )
75
77
}
76
78
77
- impl < F : FileFormat > FromStr for OffsetTemplate < F > {
79
+ impl < F : FileFormat > FromStr for SortedTemplate < F > {
78
80
type Err = Error ;
79
81
fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
80
82
let ( s, offset) = s. rsplit_once ( "\n " ) . ok_or ( Error ) ?;
81
83
let offset = offset. strip_prefix ( F :: COMMENT_START ) . ok_or ( Error ) ?;
82
84
let offset = offset. strip_suffix ( F :: COMMENT_END ) . ok_or ( Error ) ?;
83
85
let offset: Offset = serde_json:: from_str ( & offset) . map_err ( |_| Error ) ?;
84
86
let ( before, mut s) = checked_split_at ( s, offset. start ) . ok_or ( Error ) ?;
85
- let mut contents = Vec :: default ( ) ;
87
+ let mut contents = BTreeSet :: default ( ) ;
86
88
let mut sep = "" ;
87
89
for & index in offset. delta . iter ( ) {
88
90
let ( content, rest) = checked_split_at ( s, index) . ok_or ( Error ) ?;
89
91
s = rest;
90
92
let content = content. strip_prefix ( sep) . ok_or ( Error ) ?;
91
- contents. push ( content) ;
93
+ contents. insert ( content. to_string ( ) ) ;
92
94
sep = F :: SEPARATOR ;
93
95
}
94
- Ok ( OffsetTemplate {
96
+ Ok ( SortedTemplate {
95
97
format : PhantomData ,
96
98
before : before. to_string ( ) ,
97
99
after : s. to_string ( ) ,
98
- contents : contents . into_iter ( ) . map ( ToString :: to_string ) . collect ( ) ,
100
+ contents,
99
101
} )
100
102
}
101
103
}
@@ -142,21 +144,21 @@ mod tests {
142
144
s. starts_with ( "//" )
143
145
}
144
146
145
- /// not correct, but good enough for these tests
146
147
fn is_comment_html ( s : & str ) -> bool {
148
+ // not correct but good enough for these tests
147
149
s. starts_with ( "<!--" ) && s. ends_with ( "-->" )
148
150
}
149
151
150
152
#[ test]
151
153
fn html_from_empty ( ) {
152
- let inserts = [ "<p>hello</p>" , "<p>kind</p>" , "<p>world</p>" ] ;
153
- let mut template = OffsetTemplate :: < Html > :: before_after ( "" , "" ) ;
154
+ let inserts = [ "<p>hello</p>" , "<p>kind</p>" , "<p>hello</p>" , "<p> world</p>"] ;
155
+ let mut template = SortedTemplate :: < Html > :: before_after ( "" , "" ) ;
154
156
for insert in inserts {
155
157
template. append ( insert. to_string ( ) ) ;
156
158
}
157
159
let template = format ! ( "{template}" ) ;
158
160
let ( template, end) = template. rsplit_once ( "\n " ) . unwrap ( ) ;
159
- assert_eq ! ( template, inserts . join ( "" ) ) ;
161
+ assert_eq ! ( template, "<p>hello</p><p>kind</p><p>world</p>" ) ;
160
162
assert ! ( is_comment_html( end) ) ;
161
163
assert ! ( !end. contains( "\n " ) ) ;
162
164
}
@@ -166,7 +168,7 @@ mod tests {
166
168
let inserts = [ "<p>hello</p>" , "<p>kind</p>" , "<p>world</p>" ] ;
167
169
let before = "<html><head></head><body>" ;
168
170
let after = "</body>" ;
169
- let mut template = OffsetTemplate :: < Html > :: before_after ( before, after) ;
171
+ let mut template = SortedTemplate :: < Html > :: before_after ( before, after) ;
170
172
for insert in inserts {
171
173
template. append ( insert. to_string ( ) ) ;
172
174
}
@@ -179,21 +181,21 @@ mod tests {
179
181
180
182
#[ test]
181
183
fn js_from_empty ( ) {
182
- let inserts = [ "1" , "2" , "3 " ] ;
183
- let mut template = OffsetTemplate :: < Js > :: before_after ( "" , "" ) ;
184
+ let inserts = [ "1" , "2" , "2" , "2" , "3" , "1 "] ;
185
+ let mut template = SortedTemplate :: < Js > :: before_after ( "" , "" ) ;
184
186
for insert in inserts {
185
187
template. append ( insert. to_string ( ) ) ;
186
188
}
187
189
let template = format ! ( "{template}" ) ;
188
190
let ( template, end) = template. rsplit_once ( "\n " ) . unwrap ( ) ;
189
- assert_eq ! ( template, inserts . join ( "," ) ) ;
191
+ assert_eq ! ( template, "1,2,3" ) ;
190
192
assert ! ( is_comment_js( end) ) ;
191
193
assert ! ( !end. contains( "\n " ) ) ;
192
194
}
193
195
194
196
#[ test]
195
197
fn js_empty_array ( ) {
196
- let template = OffsetTemplate :: < Js > :: before_after ( "[" , "]" ) ;
198
+ let template = SortedTemplate :: < Js > :: before_after ( "[" , "]" ) ;
197
199
let template = format ! ( "{template}" ) ;
198
200
let ( template, end) = template. rsplit_once ( "\n " ) . unwrap ( ) ;
199
201
assert_eq ! ( template, format!( "[]" ) ) ;
@@ -204,7 +206,7 @@ mod tests {
204
206
#[ test]
205
207
fn js_number_array ( ) {
206
208
let inserts = [ "1" , "2" , "3" ] ;
207
- let mut template = OffsetTemplate :: < Js > :: before_after ( "[" , "]" ) ;
209
+ let mut template = SortedTemplate :: < Js > :: before_after ( "[" , "]" ) ;
208
210
for insert in inserts {
209
211
template. append ( insert. to_string ( ) ) ;
210
212
}
@@ -217,8 +219,8 @@ mod tests {
217
219
218
220
#[ test]
219
221
fn magic_js_number_array ( ) {
220
- let inserts = [ "1" ] ;
221
- let mut template = OffsetTemplate :: < Js > :: magic ( "[#]" , "#" ) . unwrap ( ) ;
222
+ let inserts = [ "1" , "1" ] ;
223
+ let mut template = SortedTemplate :: < Js > :: magic ( "[#]" , "#" ) . unwrap ( ) ;
222
224
for insert in inserts {
223
225
template. append ( insert. to_string ( ) ) ;
224
226
}
@@ -232,12 +234,12 @@ mod tests {
232
234
#[ test]
233
235
fn round_trip_js ( ) {
234
236
let inserts = [ "1" , "2" , "3" ] ;
235
- let mut template = OffsetTemplate :: < Js > :: before_after ( "[" , "]" ) ;
237
+ let mut template = SortedTemplate :: < Js > :: before_after ( "[" , "]" ) ;
236
238
for insert in inserts {
237
239
template. append ( insert. to_string ( ) ) ;
238
240
}
239
241
let template1 = format ! ( "{template}" ) ;
240
- let mut template = OffsetTemplate :: < Js > :: from_str ( & template1) . unwrap ( ) ;
242
+ let mut template = SortedTemplate :: < Js > :: from_str ( & template1) . unwrap ( ) ;
241
243
assert_eq ! ( template1, format!( "{template}" ) ) ;
242
244
template. append ( "4" . to_string ( ) ) ;
243
245
let template = format ! ( "{template}" ) ;
@@ -248,34 +250,34 @@ mod tests {
248
250
249
251
#[ test]
250
252
fn round_trip_html ( ) {
251
- let inserts = [ "<p>hello</p>" , "<p>kind</p>" , "<p>world</p>" ] ;
253
+ let inserts = [ "<p>hello</p>" , "<p>kind</p>" , "<p>world</p>" , "<p>kind</p>" ] ;
252
254
let before = "<html><head></head><body>" ;
253
255
let after = "</body>" ;
254
- let mut template = OffsetTemplate :: < Html > :: before_after ( before, after) ;
256
+ let mut template = SortedTemplate :: < Html > :: before_after ( before, after) ;
255
257
template. append ( inserts[ 0 ] . to_string ( ) ) ;
256
258
template. append ( inserts[ 1 ] . to_string ( ) ) ;
257
259
let template = format ! ( "{template}" ) ;
258
- let mut template = OffsetTemplate :: < Html > :: from_str ( & template) . unwrap ( ) ;
260
+ let mut template = SortedTemplate :: < Html > :: from_str ( & template) . unwrap ( ) ;
259
261
template. append ( inserts[ 2 ] . to_string ( ) ) ;
260
262
let template = format ! ( "{template}" ) ;
261
263
let ( template, end) = template. rsplit_once ( "\n " ) . unwrap ( ) ;
262
- assert_eq ! ( template, format!( "{before}{}{ after}" , inserts . join ( "" ) ) ) ;
264
+ assert_eq ! ( template, format!( "{before}<p>hello</p><p>kind</p><p>world</p>{ after}" ) ) ;
263
265
assert ! ( is_comment_html( end) ) ;
264
266
}
265
267
266
268
#[ test]
267
269
fn blank_js ( ) {
268
270
let inserts = [ "1" , "2" , "3" ] ;
269
- let mut template = OffsetTemplate :: < Js > :: before_after ( "" , "" ) ;
271
+ let template = SortedTemplate :: < Js > :: before_after ( "" , "" ) ;
270
272
let template = format ! ( "{template}" ) ;
271
273
let ( t, _) = template. rsplit_once ( "\n " ) . unwrap ( ) ;
272
274
assert_eq ! ( t, "" ) ;
273
- let mut template = OffsetTemplate :: < Js > :: from_str ( & template) . unwrap ( ) ;
275
+ let mut template = SortedTemplate :: < Js > :: from_str ( & template) . unwrap ( ) ;
274
276
for insert in inserts {
275
277
template. append ( insert. to_string ( ) ) ;
276
278
}
277
279
let template1 = format ! ( "{template}" ) ;
278
- let mut template = OffsetTemplate :: < Js > :: from_str ( & template1) . unwrap ( ) ;
280
+ let mut template = SortedTemplate :: < Js > :: from_str ( & template1) . unwrap ( ) ;
279
281
assert_eq ! ( template1, format!( "{template}" ) ) ;
280
282
template. append ( "4" . to_string ( ) ) ;
281
283
let template = format ! ( "{template}" ) ;
0 commit comments