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 if pos >= len || bytes[pos] == b',' || bytes[pos] == b';' {
81 return Err(DecodeError::InvalidSegmentLength { fields: 2, offset: pos });
82 }
83
84 let (delta, consumed) = vlq_decode(bytes, pos)?;
86 original_line += delta;
87 pos += consumed;
88
89 if pos >= len || bytes[pos] == b',' || bytes[pos] == b';' {
91 return Err(DecodeError::InvalidSegmentLength { fields: 3, offset: pos });
92 }
93
94 let (delta, consumed) = vlq_decode(bytes, pos)?;
96 original_column += delta;
97 pos += consumed;
98
99 if pos < len && bytes[pos] != b',' && bytes[pos] != b';' {
101 let (delta, consumed) = vlq_decode(bytes, pos)?;
102 name_index += delta;
103 pos += consumed;
104 Segment::five(
105 generated_column,
106 source_index,
107 original_line,
108 original_column,
109 name_index,
110 )
111 } else {
112 Segment::four(generated_column, source_index, original_line, original_column)
113 }
114 } else {
115 Segment::one(generated_column)
116 };
117
118 line.push(segment);
119 }
120
121 mappings.push(line);
122
123 if !saw_semicolon {
124 break;
125 }
126 }
127
128 Ok(mappings)
129}