@@ -3,40 +3,75 @@ use crate::Mapping;
33const B64_CHARS : & [ u8 ] =
44 b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
55
6- pub fn encode_vlq ( out : & mut Vec < u8 > , a : u32 , b : u32 ) {
6+ /// Encode a VLQ diff (a relative to b) into `out`.
7+ ///
8+ /// Uses a stack buffer to batch the write, avoiding per-byte `Vec::push`
9+ /// bounds checks.
10+ #[ inline( always) ]
11+ fn encode_vlq ( out : & mut Vec < u8 > , a : u32 , b : u32 ) {
712 let mut num = if a >= b {
813 ( a - b) << 1
914 } else {
1015 ( ( b - a) << 1 ) + 1
1116 } ;
1217
18+ // A VLQ for u32 needs at most ceil(32/5)+1 = 7 base64 characters.
19+ let mut buf = [ 0u8 ; 7 ] ;
20+ let mut len = 0 ;
21+
1322 loop {
1423 let mut digit = num & 0b11111 ;
1524 num >>= 5 ;
1625 if num > 0 {
1726 digit |= 1 << 5 ;
1827 }
19- out. push ( B64_CHARS [ digit as usize ] ) ;
28+ buf[ len] = B64_CHARS [ digit as usize ] ;
29+ len += 1 ;
2030 if num == 0 {
2131 break ;
2232 }
2333 }
34+
35+ out. extend_from_slice ( & buf[ ..len] ) ;
2436}
2537
26- pub ( crate ) trait MappingsEncoder {
27- fn encode ( & mut self , mapping : & Mapping ) ;
28- fn drain ( & mut self ) -> String ;
38+ /// A source map mappings encoder that eliminates dynamic dispatch by using
39+ /// an enum instead of `Box<dyn Trait>`.
40+ pub ( crate ) enum MappingsEncoder {
41+ Full ( FullMappingsEncoder ) ,
42+ LinesOnly ( LinesOnlyMappingsEncoder ) ,
2943}
3044
31- pub fn create_encoder ( columns : bool ) -> Box < dyn MappingsEncoder > {
32- if columns {
33- Box :: new ( FullMappingsEncoder :: new ( ) )
34- } else {
35- Box :: new ( LinesOnlyMappingsEncoder :: new ( ) )
45+ impl MappingsEncoder {
46+ /// Create a new encoder. `columns: true` produces full mappings,
47+ /// `columns: false` produces lines-only mappings.
48+ #[ inline]
49+ pub fn new ( columns : bool ) -> Self {
50+ if columns {
51+ Self :: Full ( FullMappingsEncoder :: new ( ) )
52+ } else {
53+ Self :: LinesOnly ( LinesOnlyMappingsEncoder :: new ( ) )
54+ }
55+ }
56+
57+ #[ inline]
58+ pub fn encode ( & mut self , mapping : & Mapping ) {
59+ match self {
60+ Self :: Full ( enc) => enc. encode ( mapping) ,
61+ Self :: LinesOnly ( enc) => enc. encode ( mapping) ,
62+ }
63+ }
64+
65+ #[ inline]
66+ pub fn drain ( & mut self ) -> String {
67+ match self {
68+ Self :: Full ( enc) => enc. drain ( ) ,
69+ Self :: LinesOnly ( enc) => enc. drain ( ) ,
70+ }
3671 }
3772}
3873
39- struct FullMappingsEncoder {
74+ pub ( crate ) struct FullMappingsEncoder {
4075 current_line : u32 ,
4176 current_column : u32 ,
4277 current_original_line : u32 ,
@@ -50,7 +85,7 @@ struct FullMappingsEncoder {
5085}
5186
5287impl FullMappingsEncoder {
53- pub fn new ( ) -> Self {
88+ fn new ( ) -> Self {
5489 Self {
5590 current_line : 1 ,
5691 current_column : 0 ,
@@ -64,9 +99,7 @@ impl FullMappingsEncoder {
6499 mappings : Default :: default ( ) ,
65100 }
66101 }
67- }
68102
69- impl MappingsEncoder for FullMappingsEncoder {
70103 fn encode ( & mut self , mapping : & Mapping ) {
71104 if self . active_mapping && self . current_line == mapping. generated_line {
72105 // A mapping is still active
@@ -89,8 +122,10 @@ impl MappingsEncoder for FullMappingsEncoder {
89122 }
90123
91124 if self . current_line < mapping. generated_line {
92- ( 0 ..mapping. generated_line - self . current_line )
93- . for_each ( |_| self . mappings . push ( b';' ) ) ;
125+ let delta = ( mapping. generated_line - self . current_line ) as usize ;
126+ self
127+ . mappings
128+ . extend ( std:: iter:: repeat_n ( b';' , delta) ) ;
94129 self . current_line = mapping. generated_line ;
95130 self . current_column = 0 ;
96131 self . initial = false ;
@@ -173,9 +208,7 @@ impl LinesOnlyMappingsEncoder {
173208 mappings : Default :: default ( ) ,
174209 }
175210 }
176- }
177211
178- impl MappingsEncoder for LinesOnlyMappingsEncoder {
179212 fn encode ( & mut self , mapping : & Mapping ) {
180213 if let Some ( original) = & mapping. original {
181214 if self . last_written_line == mapping. generated_line {
@@ -196,9 +229,9 @@ impl MappingsEncoder for LinesOnlyMappingsEncoder {
196229 if original. source_index == self . current_source_index {
197230 if original. original_line == self . current_original_line + 1 {
198231 self . current_original_line = original. original_line ;
199- self . mappings . extend ( b"AACA" ) ;
232+ self . mappings . extend_from_slice ( b"AACA" ) ;
200233 } else {
201- self . mappings . extend ( b"AA" ) ;
234+ self . mappings . extend_from_slice ( b"AA" ) ;
202235 encode_vlq (
203236 & mut self . mappings ,
204237 original. original_line ,
@@ -208,7 +241,7 @@ impl MappingsEncoder for LinesOnlyMappingsEncoder {
208241 self . mappings . push ( b'A' ) ;
209242 }
210243 } else {
211- self . mappings . extend ( b"A" ) ;
244+ self . mappings . push ( b'A' ) ;
212245 encode_vlq (
213246 & mut self . mappings ,
214247 original. source_index ,
0 commit comments