1use crate::SourceMapMappings;
2use crate::vlq::vlq_encode_unchecked;
3
4pub fn encode(mappings: &SourceMapMappings) -> String {
11 if mappings.is_empty() {
12 return String::new();
13 }
14
15 let segment_count: usize = mappings.iter().map(|line| line.len()).sum();
18 let mut buf: Vec<u8> = Vec::with_capacity(segment_count * 7 * 5 + mappings.len());
19
20 let mut prev_source: i64 = 0;
22 let mut prev_original_line: i64 = 0;
23 let mut prev_original_column: i64 = 0;
24 let mut prev_name: i64 = 0;
25
26 for (line_idx, line) in mappings.iter().enumerate() {
27 if line_idx > 0 {
28 buf.push(b';');
29 }
30
31 let mut prev_generated_column: i64 = 0;
33 let mut wrote_segment = false;
34
35 for segment in line.iter() {
36 if segment.is_empty() {
37 continue;
38 }
39
40 if wrote_segment {
41 buf.push(b',');
42 }
43 wrote_segment = true;
44
45 unsafe {
49 vlq_encode_unchecked(&mut buf, segment[0] - prev_generated_column);
51 prev_generated_column = segment[0];
52
53 if segment.len() >= 4 {
54 vlq_encode_unchecked(&mut buf, segment[1] - prev_source);
56 prev_source = segment[1];
57
58 vlq_encode_unchecked(&mut buf, segment[2] - prev_original_line);
60 prev_original_line = segment[2];
61
62 vlq_encode_unchecked(&mut buf, segment[3] - prev_original_column);
64 prev_original_column = segment[3];
65
66 if segment.len() >= 5 {
67 vlq_encode_unchecked(&mut buf, segment[4] - prev_name);
69 prev_name = segment[4];
70 }
71 }
72 }
73 }
74 }
75
76 debug_assert!(buf.is_ascii());
79 unsafe { String::from_utf8_unchecked(buf) }
80}
81
82#[cfg(feature = "parallel")]
87fn encode_line_to_bytes(
88 segments: &[crate::Segment],
89 init_source: i64,
90 init_original_line: i64,
91 init_original_column: i64,
92 init_name: i64,
93) -> Vec<u8> {
94 let mut buf = Vec::with_capacity(segments.len() * 7 * 5);
95 let mut prev_generated_column: i64 = 0;
96 let mut prev_source = init_source;
97 let mut prev_original_line = init_original_line;
98 let mut prev_original_column = init_original_column;
99 let mut prev_name = init_name;
100 let mut wrote_segment = false;
101
102 for segment in segments {
103 if segment.is_empty() {
104 continue;
105 }
106
107 if wrote_segment {
108 buf.push(b',');
109 }
110 wrote_segment = true;
111
112 unsafe {
114 vlq_encode_unchecked(&mut buf, segment[0] - prev_generated_column);
115 prev_generated_column = segment[0];
116
117 if segment.len() >= 4 {
118 vlq_encode_unchecked(&mut buf, segment[1] - prev_source);
119 prev_source = segment[1];
120
121 vlq_encode_unchecked(&mut buf, segment[2] - prev_original_line);
122 prev_original_line = segment[2];
123
124 vlq_encode_unchecked(&mut buf, segment[3] - prev_original_column);
125 prev_original_column = segment[3];
126
127 if segment.len() >= 5 {
128 vlq_encode_unchecked(&mut buf, segment[4] - prev_name);
129 prev_name = segment[4];
130 }
131 }
132 }
133 }
134
135 buf
136}
137
138#[cfg(feature = "parallel")]
147pub fn encode_parallel(mappings: &SourceMapMappings) -> String {
148 use rayon::prelude::*;
149
150 if mappings.is_empty() {
151 return String::new();
152 }
153
154 let total_segments: usize = mappings.iter().map(|l| l.len()).sum();
155 if mappings.len() < 1024 || total_segments < 4096 {
156 return encode(mappings);
157 }
158
159 let mut states: Vec<(i64, i64, i64, i64)> = Vec::with_capacity(mappings.len());
161 let mut prev_source: i64 = 0;
162 let mut prev_original_line: i64 = 0;
163 let mut prev_original_column: i64 = 0;
164 let mut prev_name: i64 = 0;
165
166 for line in mappings.iter() {
167 states.push((
168 prev_source,
169 prev_original_line,
170 prev_original_column,
171 prev_name,
172 ));
173 for segment in line.iter() {
174 if segment.len() >= 4 {
175 prev_source = segment[1];
176 prev_original_line = segment[2];
177 prev_original_column = segment[3];
178 if segment.len() >= 5 {
179 prev_name = segment[4];
180 }
181 }
182 }
183 }
184
185 let encoded_lines: Vec<Vec<u8>> = mappings
187 .par_iter()
188 .zip(states.par_iter())
189 .map(|(line, &(src, ol, oc, name))| encode_line_to_bytes(line, src, ol, oc, name))
190 .collect();
191
192 let total_len: usize =
194 encoded_lines.iter().map(|l| l.len()).sum::<usize>() + encoded_lines.len() - 1;
195 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
196 for (i, line_bytes) in encoded_lines.iter().enumerate() {
197 if i > 0 {
198 buf.push(b';');
199 }
200 buf.extend_from_slice(line_bytes);
201 }
202
203 debug_assert!(buf.is_ascii());
206 unsafe { String::from_utf8_unchecked(buf) }
207}