11use std:: {
22 borrow:: Cow ,
33 cell:: RefCell ,
4+ collections:: BTreeSet ,
45 hash:: { Hash , Hasher } ,
5- sync:: {
6- atomic:: { AtomicBool , Ordering } ,
7- Arc , Mutex ,
8- } ,
6+ sync:: Arc ,
97} ;
108
11- use itertools:: Itertools ;
129use rustc_hash:: FxHashMap as HashMap ;
1310
1411use crate :: {
@@ -41,10 +38,7 @@ use crate::{
4138/// ```
4239pub struct ReplaceSource < T > {
4340 inner : Arc < T > ,
44- replacements : Vec < Replacement > ,
45- sorted_index : Mutex < Vec < usize > > ,
46- /// Whether `replacements` is sorted.
47- is_sorted : AtomicBool ,
41+ replacements : BTreeSet < ( Replacement , u32 ) > ,
4842}
4943
5044/// Enforce replacement order when two replacement start and end are both equal
@@ -68,6 +62,22 @@ struct Replacement {
6862 enforce : ReplacementEnforce ,
6963}
7064
65+ impl Ord for Replacement {
66+ fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
67+ ( self . start , self . end , self . enforce ) . cmp ( & (
68+ other. start ,
69+ other. end ,
70+ other. enforce ,
71+ ) )
72+ }
73+ }
74+
75+ impl PartialOrd for Replacement {
76+ fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
77+ Some ( self . cmp ( other) )
78+ }
79+ }
80+
7181impl Replacement {
7282 pub fn new (
7383 start : u32 ,
@@ -91,42 +101,14 @@ impl<T> ReplaceSource<T> {
91101 pub fn new ( source : T ) -> Self {
92102 Self {
93103 inner : Arc :: new ( source) ,
94- replacements : Vec :: new ( ) ,
95- sorted_index : Mutex :: new ( Vec :: new ( ) ) ,
96- is_sorted : AtomicBool :: new ( true ) ,
104+ replacements : BTreeSet :: new ( ) ,
97105 }
98106 }
99107
100108 /// Get the original [Source].
101109 pub fn original ( & self ) -> & T {
102110 & self . inner
103111 }
104-
105- fn sort_replacement ( & self ) {
106- if self . is_sorted . load ( Ordering :: SeqCst ) {
107- return ;
108- }
109- let sorted_index = self
110- . replacements
111- . iter ( )
112- . enumerate ( )
113- . sorted_by ( |( _, a) , ( _, b) | {
114- ( a. start , a. end , a. enforce ) . cmp ( & ( b. start , b. end , b. enforce ) )
115- } )
116- . map ( |replacement| replacement. 0 )
117- . collect :: < Vec < _ > > ( ) ;
118- * self . sorted_index . lock ( ) . unwrap ( ) = sorted_index;
119- self . is_sorted . store ( true , Ordering :: SeqCst )
120- }
121-
122- fn sorted_replacement ( & self ) -> Vec < & Replacement > {
123- self . sort_replacement ( ) ;
124- let sorted_index = self . sorted_index . lock ( ) . unwrap ( ) ;
125- sorted_index
126- . iter ( )
127- . map ( |idx| & self . replacements [ * idx] )
128- . collect ( )
129- }
130112}
131113
132114impl < T : Source > ReplaceSource < T > {
@@ -154,14 +136,16 @@ impl<T: Source> ReplaceSource<T> {
154136 content : & str ,
155137 name : Option < & str > ,
156138 ) {
157- self . replacements . push ( Replacement :: new (
158- start,
159- end,
160- content. into ( ) ,
161- name. map ( |s| s. into ( ) ) ,
162- ReplacementEnforce :: Normal ,
139+ self . replacements . insert ( (
140+ Replacement :: new (
141+ start,
142+ end,
143+ content. into ( ) ,
144+ name. map ( |s| s. into ( ) ) ,
145+ ReplacementEnforce :: Normal ,
146+ ) ,
147+ self . replacements . len ( ) as u32 ,
163148 ) ) ;
164- self . is_sorted . store ( false , Ordering :: SeqCst ) ;
165149 }
166150
167151 /// Create a replacement with content at `[start, end)`, with ReplacementEnforce.
@@ -173,14 +157,16 @@ impl<T: Source> ReplaceSource<T> {
173157 name : Option < & str > ,
174158 enforce : ReplacementEnforce ,
175159 ) {
176- self . replacements . push ( Replacement :: new (
177- start,
178- end,
179- content. into ( ) ,
180- name. map ( |s| s. into ( ) ) ,
181- enforce,
160+ self . replacements . insert ( (
161+ Replacement :: new (
162+ start,
163+ end,
164+ content. into ( ) ,
165+ name. map ( |s| s. into ( ) ) ,
166+ enforce,
167+ ) ,
168+ self . replacements . len ( ) as u32 ,
182169 ) ) ;
183- self . is_sorted . store ( false , Ordering :: SeqCst ) ;
184170 }
185171}
186172
@@ -190,18 +176,18 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> Source for ReplaceSource<T> {
190176
191177 // mut_string_push_str is faster that vec join
192178 // concatenate strings benchmark, see https://github.com/hoodie/concatenation_benchmarks-rs
193- let replacements = self . sorted_replacement ( ) ;
194- if replacements. is_empty ( ) {
179+ if self . replacements . is_empty ( ) {
195180 return inner_source_code;
196181 }
197- let max_len = replacements
182+ let max_len = self
183+ . replacements
198184 . iter ( )
199- . map ( |replacement| replacement. content . len ( ) )
185+ . map ( |( replacement, _ ) | replacement. content . len ( ) )
200186 . sum :: < usize > ( )
201187 + inner_source_code. len ( ) ;
202188 let mut source_code = String :: with_capacity ( max_len) ;
203189 let mut inner_pos = 0 ;
204- for replacement in replacements. iter ( ) {
190+ for ( replacement, _ ) in self . replacements . iter ( ) {
205191 if inner_pos < replacement. start {
206192 let end_pos = ( replacement. start as usize ) . min ( inner_source_code. len ( ) ) ;
207193 source_code. push_str ( & inner_source_code[ inner_pos as usize ..end_pos] ) ;
@@ -226,13 +212,12 @@ impl<T: Source + Hash + PartialEq + Eq + 'static> Source for ReplaceSource<T> {
226212
227213 // mut_string_push_str is faster that vec join
228214 // concatenate strings benchmark, see https://github.com/hoodie/concatenation_benchmarks-rs
229- let replacements = self . sorted_replacement ( ) ;
230- if replacements. is_empty ( ) {
215+ if self . replacements . is_empty ( ) {
231216 return inner_source_code;
232217 }
233218 let mut source_code = Rope :: new ( ) ;
234219 let mut inner_pos = 0 ;
235- for replacement in replacements. iter ( ) {
220+ for ( replacement, _ ) in self . replacements . iter ( ) {
236221 if inner_pos < replacement. start {
237222 let end_pos = ( replacement. start as usize ) . min ( inner_source_code. len ( ) ) ;
238223 let slice = inner_source_code. byte_slice ( inner_pos as usize ..end_pos) ;
@@ -288,7 +273,6 @@ impl<T: std::fmt::Debug> std::fmt::Debug for ReplaceSource<T> {
288273 "replacements" ,
289274 & self . replacements . iter ( ) . take ( 3 ) . collect :: < Vec < _ > > ( ) ,
290275 )
291- . field ( "is_sorted" , & self . is_sorted . load ( Ordering :: SeqCst ) )
292276 . finish ( )
293277 }
294278}
@@ -330,11 +314,10 @@ impl<T: Source> StreamChunks for ReplaceSource<T> {
330314 on_name : crate :: helpers:: OnName < ' _ , ' a > ,
331315 ) -> crate :: helpers:: GeneratedInfo {
332316 let on_name = RefCell :: new ( on_name) ;
333- let repls = & self . sorted_replacement ( ) ;
317+ let mut replacements = self . replacements . iter ( ) . map ( | ( r , _ ) | r ) ;
334318 let mut pos: u32 = 0 ;
335- let mut i: usize = 0 ;
336319 let mut replacement_end: Option < u32 > = None ;
337- let mut next_replacement = ( i < repls . len ( ) ) . then ( || repls [ i ] . start ) ;
320+ let mut next_replacement = replacements . next ( ) ;
338321 let mut generated_line_offset: i64 = 0 ;
339322 let mut generated_column_offset: i64 = 0 ;
340323 let mut generated_column_offset_line = 0 ;
@@ -449,13 +432,13 @@ impl<T: Source> StreamChunks for ReplaceSource<T> {
449432 }
450433
451434 // Is a replacement in the chunk?
452- while let Some ( next_replacement_pos ) = next_replacement
453- . filter ( |next_replacement_pos| * next_replacement_pos < end_pos)
435+ while let Some ( replacement ) =
436+ next_replacement . filter ( |replacement| replacement . start < end_pos)
454437 {
455438 let mut line = mapping. generated_line as i64 + generated_line_offset;
456- if next_replacement_pos > pos {
439+ if replacement . start > pos {
457440 // Emit chunk until replacement
458- let offset = next_replacement_pos - pos;
441+ let offset = replacement . start - pos;
459442 let chunk_slice = chunk
460443 . byte_slice ( chunk_pos as usize ..( chunk_pos + offset) as usize ) ;
461444 on_chunk (
@@ -482,7 +465,7 @@ impl<T: Source> StreamChunks for ReplaceSource<T> {
482465 ) ;
483466 mapping. generated_column += offset;
484467 chunk_pos += offset;
485- pos = next_replacement_pos ;
468+ pos = replacement . start ;
486469 if let Some ( original) =
487470 mapping. original . as_mut ( ) . filter ( |original| {
488471 check_original_content (
@@ -497,20 +480,16 @@ impl<T: Source> StreamChunks for ReplaceSource<T> {
497480 }
498481 }
499482 // Insert replacement content split into chunks by lines
500- #[ allow( unsafe_code) ]
501- // SAFETY: The safety of this operation relies on the fact that the `ReplaceSource` type will not delete the `replacements` during its entire lifetime.
502- let repl = unsafe {
503- std:: mem:: transmute :: < & Replacement , & ' a Replacement > ( repls[ i] )
504- } ;
505-
506483 let lines =
507- split_into_lines ( & repl . content . as_str ( ) ) . collect :: < Vec < _ > > ( ) ;
484+ split_into_lines ( & replacement . content . as_str ( ) ) . collect :: < Vec < _ > > ( ) ;
508485 let mut replacement_name_index = mapping
509486 . original
510487 . as_ref ( )
511488 . and_then ( |original| original. name_index ) ;
512- if let Some ( name) =
513- repl. name . as_ref ( ) . filter ( |_| mapping. original . is_some ( ) )
489+ if let Some ( name) = replacement
490+ . name
491+ . as_ref ( )
492+ . filter ( |_| mapping. original . is_some ( ) )
514493 {
515494 let mut name_mapping = name_mapping. borrow_mut ( ) ;
516495 let mut global_index = name_mapping. get ( name. as_str ( ) ) . copied ( ) ;
@@ -563,18 +542,13 @@ impl<T: Source> StreamChunks for ReplaceSource<T> {
563542
564543 // Remove replaced content by settings this variable
565544 replacement_end = if let Some ( replacement_end) = replacement_end {
566- Some ( replacement_end. max ( repl . end ) )
545+ Some ( replacement_end. max ( replacement . end ) )
567546 } else {
568- Some ( repl . end )
547+ Some ( replacement . end )
569548 } ;
570549
571550 // Move to next replacement
572- i += 1 ;
573- next_replacement = if i < repls. len ( ) {
574- Some ( repls[ i] . start )
575- } else {
576- None
577- } ;
551+ next_replacement = replacements. next ( ) ;
578552
579553 // Skip over when it has been replaced
580554 let offset = chunk. len ( ) as i64 - end_pos as i64
@@ -687,9 +661,8 @@ impl<T: Source> StreamChunks for ReplaceSource<T> {
687661
688662 // Handle remaining replacements
689663 let mut remainder = Rope :: new ( ) ;
690- while i < repls. len ( ) {
691- remainder. add ( & repls[ i] . content ) ;
692- i += 1 ;
664+ for replacement in replacements {
665+ remainder. add ( & replacement. content ) ;
693666 }
694667
695668 // Insert remaining replacements content split into chunks by lines
@@ -742,16 +715,14 @@ impl<T: Source> Clone for ReplaceSource<T> {
742715 Self {
743716 inner : self . inner . clone ( ) ,
744717 replacements : self . replacements . clone ( ) ,
745- sorted_index : Mutex :: new ( self . sorted_index . lock ( ) . unwrap ( ) . clone ( ) ) ,
746- is_sorted : AtomicBool :: new ( self . is_sorted . load ( Ordering :: SeqCst ) ) ,
747718 }
748719 }
749720}
750721
751722impl < T : Hash > Hash for ReplaceSource < T > {
752723 fn hash < H : Hasher > ( & self , state : & mut H ) {
753724 "ReplaceSource" . hash ( state) ;
754- for repl in self . sorted_replacement ( ) {
725+ for ( repl, _ ) in self . replacements . iter ( ) {
755726 repl. hash ( state) ;
756727 }
757728 self . inner . hash ( state) ;
0 commit comments