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 unsafe { String::from_utf8_unchecked(buf) }
72}
73
74#[cfg(feature = "parallel")]
79fn encode_line_to_bytes(
80 segments: &[crate::Segment],
81 init_source: i64,
82 init_original_line: i64,
83 init_original_column: i64,
84 init_name: i64,
85) -> Vec<u8> {
86 let mut buf = Vec::with_capacity(segments.len() * 6);
87 let mut prev_generated_column: i64 = 0;
88 let mut prev_source = init_source;
89 let mut prev_original_line = init_original_line;
90 let mut prev_original_column = init_original_column;
91 let mut prev_name = init_name;
92 let mut wrote_segment = false;
93
94 for segment in segments {
95 if segment.is_empty() {
96 continue;
97 }
98
99 if wrote_segment {
100 buf.push(b',');
101 }
102 wrote_segment = true;
103
104 vlq_encode(&mut buf, segment[0] - prev_generated_column);
105 prev_generated_column = segment[0];
106
107 if segment.len() >= 4 {
108 vlq_encode(&mut buf, segment[1] - prev_source);
109 prev_source = segment[1];
110
111 vlq_encode(&mut buf, segment[2] - prev_original_line);
112 prev_original_line = segment[2];
113
114 vlq_encode(&mut buf, segment[3] - prev_original_column);
115 prev_original_column = segment[3];
116
117 if segment.len() >= 5 {
118 vlq_encode(&mut buf, segment[4] - prev_name);
119 prev_name = segment[4];
120 }
121 }
122 }
123
124 buf
125}
126
127#[cfg(feature = "parallel")]
136pub fn encode_parallel(mappings: &SourceMapMappings) -> String {
137 use rayon::prelude::*;
138
139 if mappings.is_empty() {
140 return String::new();
141 }
142
143 let total_segments: usize = mappings.iter().map(|l| l.len()).sum();
144 if mappings.len() < 1024 || total_segments < 4096 {
145 return encode(mappings);
146 }
147
148 let mut states: Vec<(i64, i64, i64, i64)> = Vec::with_capacity(mappings.len());
150 let mut prev_source: i64 = 0;
151 let mut prev_original_line: i64 = 0;
152 let mut prev_original_column: i64 = 0;
153 let mut prev_name: i64 = 0;
154
155 for line in mappings.iter() {
156 states.push((prev_source, prev_original_line, prev_original_column, prev_name));
157 for segment in line.iter() {
158 if segment.len() >= 4 {
159 prev_source = segment[1];
160 prev_original_line = segment[2];
161 prev_original_column = segment[3];
162 if segment.len() >= 5 {
163 prev_name = segment[4];
164 }
165 }
166 }
167 }
168
169 let encoded_lines: Vec<Vec<u8>> = mappings
171 .par_iter()
172 .zip(states.par_iter())
173 .map(|(line, &(src, ol, oc, name))| encode_line_to_bytes(line, src, ol, oc, name))
174 .collect();
175
176 let total_len: usize =
178 encoded_lines.iter().map(|l| l.len()).sum::<usize>() + encoded_lines.len() - 1;
179 let mut buf: Vec<u8> = Vec::with_capacity(total_len);
180 for (i, line_bytes) in encoded_lines.iter().enumerate() {
181 if i > 0 {
182 buf.push(b';');
183 }
184 buf.extend_from_slice(line_bytes);
185 }
186
187 unsafe { String::from_utf8_unchecked(buf) }
189}