1use crate::SourceMapMappings;
2use crate::vlq::vlq_encode;
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();
17 let mut buf: Vec<u8> = Vec::with_capacity(segment_count * 4 + mappings.len());
18
19 let mut prev_source: i64 = 0;
21 let mut prev_original_line: i64 = 0;
22 let mut prev_original_column: i64 = 0;
23 let mut prev_name: i64 = 0;
24
25 for (line_idx, line) in mappings.iter().enumerate() {
26 if line_idx > 0 {
27 buf.push(b';');
28 }
29
30 let mut prev_generated_column: i64 = 0;
32 let mut wrote_segment = false;
33
34 for segment in line.iter() {
35 if segment.is_empty() {
36 continue;
37 }
38
39 if wrote_segment {
40 buf.push(b',');
41 }
42 wrote_segment = true;
43
44 vlq_encode(&mut buf, segment[0] - prev_generated_column);
46 prev_generated_column = segment[0];
47
48 if segment.len() >= 4 {
49 vlq_encode(&mut buf, segment[1] - prev_source);
51 prev_source = segment[1];
52
53 vlq_encode(&mut buf, segment[2] - prev_original_line);
55 prev_original_line = segment[2];
56
57 vlq_encode(&mut buf, segment[3] - prev_original_column);
59 prev_original_column = segment[3];
60
61 if segment.len() >= 5 {
62 vlq_encode(&mut buf, segment[4] - prev_name);
64 prev_name = segment[4];
65 }
66 }
67 }
68 }
69
70 debug_assert!(buf.is_ascii());
73 unsafe { String::from_utf8_unchecked(buf) }
74}
75
76#[cfg(feature = "parallel")]
81fn encode_line_to_bytes(
82 segments: &[crate::Segment],
83 init_source: i64,
84 init_original_line: i64,
85 init_original_column: i64,
86 init_name: i64,
87) -> Vec<u8> {
88 let mut buf = Vec::with_capacity(segments.len() * 6);
89 let mut prev_generated_column: i64 = 0;
90 let mut prev_source = init_source;
91 let mut prev_original_line = init_original_line;
92 let mut prev_original_column = init_original_column;
93 let mut prev_name = init_name;
94 let mut wrote_segment = false;
95
96 for segment in segments {
97 if segment.is_empty() {
98 continue;
99 }
100
101 if wrote_segment {
102 buf.push(b',');
103 }
104 wrote_segment = true;
105
106 vlq_encode(&mut buf, segment[0] - prev_generated_column);
107 prev_generated_column = segment[0];
108
109 if segment.len() >= 4 {
110 vlq_encode(&mut buf, segment[1] - prev_source);
111 prev_source = segment[1];
112
113 vlq_encode(&mut buf, segment[2] - prev_original_line);
114 prev_original_line = segment[2];
115
116 vlq_encode(&mut buf, segment[3] - prev_original_column);
117 prev_original_column = segment[3];
118
119 if segment.len() >= 5 {
120 vlq_encode(&mut buf, segment[4] - prev_name);
121 prev_name = segment[4];
122 }
123 }
124 }
125
126 buf
127}
128
129#[cfg(feature = "parallel")]
138pub fn encode_parallel(mappings: &SourceMapMappings) -> String {
139 use rayon::prelude::*;
140
141 if mappings.is_empty() {
142 return String::new();
143 }
144
145 let total_segments: usize = mappings.iter().map(|l| l.len()).sum();
146 if mappings.len() < 1024 || total_segments < 4096 {
147 return encode(mappings);
148 }
149
150 let mut states: Vec<(i64, i64, i64, i64)> = Vec::with_capacity(mappings.len());
152 let mut prev_source: i64 = 0;
153 let mut prev_original_line: i64 = 0;
154 let mut prev_original_column: i64 = 0;
155 let mut prev_name: i64 = 0;
156
157 for line in mappings.iter() {
158 states.push((
159 prev_source,
160 prev_original_line,
161 prev_original_column,
162 prev_name,
163 ));
164 for segment in line.iter() {
165 if segment.len() >= 4 {
166 prev_source = segment[1];
167 prev_original_line = segment[2];
168 prev_original_column = segment[3];
169 if segment.len() >= 5 {
170 prev_name = segment[4];
171 }
172 }
173 }
174 }
175
176 let encoded_lines: Vec<Vec<u8>> = mappings
178 .par_iter()
179 .zip(states.par_iter())
180 .map(|(line, &(src, ol, oc, name))| encode_line_to_bytes(line, src, ol, oc, name))
181 .collect();
182
183 let total_len: usize =
185 encoded_lines.iter().map(|l| l.len()).sum::<usize>() + encoded_lines.len() - 1;
186 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
187 for (i, line_bytes) in encoded_lines.iter().enumerate() {
188 if i > 0 {
189 buf.push(b';');
190 }
191 buf.extend_from_slice(line_bytes);
192 }
193
194 debug_assert!(buf.is_ascii());
197 unsafe { String::from_utf8_unchecked(buf) }
198}