1use crate::vlq::vlq_decode;
2use crate::{DecodeError, Line, Segment, SourceMapMappings};
3
4pub fn decode(input: &str) -> Result<SourceMapMappings, DecodeError> {
20 if input.is_empty() {
21 return Ok(Vec::new());
22 }
23
24 let bytes = input.as_bytes();
25 let len = bytes.len();
26
27 let mut semicolons = 0usize;
29 let mut commas = 0usize;
30 for &b in bytes {
31 semicolons += (b == b';') as usize;
32 commas += (b == b',') as usize;
33 }
34 let line_count = semicolons + 1;
35 let approx_segments = commas + line_count;
36 let avg_segments_per_line = approx_segments / line_count;
37 let mut mappings: SourceMapMappings = Vec::with_capacity(line_count);
38
39 let mut source_index: i64 = 0;
41 let mut original_line: i64 = 0;
42 let mut original_column: i64 = 0;
43 let mut name_index: i64 = 0;
44
45 let mut pos: usize = 0;
46
47 loop {
48 let mut generated_column: i64 = 0;
50 let mut line: Line = Vec::with_capacity(avg_segments_per_line);
51 let mut saw_semicolon = false;
52
53 while pos < len {
54 let byte = bytes[pos];
55
56 if byte == b';' {
57 pos += 1;
58 saw_semicolon = true;
59 break;
60 }
61
62 if byte == b',' {
63 pos += 1;
64 continue;
65 }
66
67 let (delta, consumed) = vlq_decode(bytes, pos)?;
69 generated_column += delta;
70 pos += consumed;
71
72 let segment: Segment = if pos < len && bytes[pos] != b',' && bytes[pos] != b';' {
74 let (delta, consumed) = vlq_decode(bytes, pos)?;
76 source_index += delta;
77 pos += consumed;
78
79 let (delta, consumed) = vlq_decode(bytes, pos)?;
80 original_line += delta;
81 pos += consumed;
82
83 let (delta, consumed) = vlq_decode(bytes, pos)?;
84 original_column += delta;
85 pos += consumed;
86
87 if pos < len && bytes[pos] != b',' && bytes[pos] != b';' {
89 let (delta, consumed) = vlq_decode(bytes, pos)?;
90 name_index += delta;
91 pos += consumed;
92 Segment::five(
93 generated_column,
94 source_index,
95 original_line,
96 original_column,
97 name_index,
98 )
99 } else {
100 Segment::four(
101 generated_column,
102 source_index,
103 original_line,
104 original_column,
105 )
106 }
107 } else {
108 Segment::one(generated_column)
109 };
110
111 line.push(segment);
112 }
113
114 mappings.push(line);
115
116 if !saw_semicolon {
117 break;
118 }
119 }
120
121 Ok(mappings)
122}