1use crate::vlq::vlq_decode;
2use crate::{DecodeError, Line, Segment, SourceMapMappings};
3
4#[derive(Default)]
5struct DecodeState {
6 source_index: i64,
7 original_line: i64,
8 original_column: i64,
9 name_index: i64,
10}
11
12pub fn decode(input: &str) -> Result<SourceMapMappings, DecodeError> {
28 if input.is_empty() {
29 return Ok(Vec::new());
30 }
31
32 let bytes = input.as_bytes();
33 let len = bytes.len();
34
35 let (line_count, avg_segments_per_line) = decode_capacity_hints(bytes);
39 let mut mappings: SourceMapMappings = Vec::with_capacity(line_count);
40
41 let mut state = DecodeState::default();
42 let mut pos: usize = 0;
43
44 loop {
45 let mut generated_column: i64 = 0;
47 let mut line: Line = Vec::with_capacity(avg_segments_per_line);
48 let mut saw_semicolon = false;
49
50 while pos < len {
51 let byte = bytes[pos];
52
53 if byte == b';' {
54 pos += 1;
55 saw_semicolon = true;
56 break;
57 }
58
59 if byte == b',' {
60 pos += 1;
61 continue;
62 }
63
64 let (delta, consumed) = vlq_decode(bytes, pos)?;
66 generated_column += delta;
67 pos += consumed;
68
69 let segment: Segment = if pos < len && bytes[pos] != b',' && bytes[pos] != b';' {
71 decode_sourced_segment(bytes, &mut pos, generated_column, &mut state)?
72 } else {
73 Segment::one(generated_column)
74 };
75
76 line.push(segment);
77 }
78
79 mappings.push(line);
80
81 if !saw_semicolon {
82 break;
83 }
84 }
85
86 Ok(mappings)
87}
88
89fn decode_capacity_hints(bytes: &[u8]) -> (usize, usize) {
90 let semicolons = memchr::memchr_iter(b';', bytes).count();
91 let commas = memchr::memchr_iter(b',', bytes).count();
92 let line_count = semicolons + 1;
93 let approx_segments = commas + line_count;
94 (line_count, approx_segments / line_count)
95}
96
97fn decode_sourced_segment(
98 bytes: &[u8],
99 pos: &mut usize,
100 generated_column: i64,
101 state: &mut DecodeState,
102) -> Result<Segment, DecodeError> {
103 let (delta, consumed) = vlq_decode(bytes, *pos)?;
104 state.source_index += delta;
105 *pos += consumed;
106
107 if *pos >= bytes.len() || bytes[*pos] == b',' || bytes[*pos] == b';' {
108 return Err(DecodeError::InvalidSegmentLength { fields: 2, offset: *pos });
109 }
110
111 let (delta, consumed) = vlq_decode(bytes, *pos)?;
112 state.original_line += delta;
113 *pos += consumed;
114
115 if *pos >= bytes.len() || bytes[*pos] == b',' || bytes[*pos] == b';' {
116 return Err(DecodeError::InvalidSegmentLength { fields: 3, offset: *pos });
117 }
118
119 let (delta, consumed) = vlq_decode(bytes, *pos)?;
120 state.original_column += delta;
121 *pos += consumed;
122
123 if *pos < bytes.len() && bytes[*pos] != b',' && bytes[*pos] != b';' {
124 let (delta, consumed) = vlq_decode(bytes, *pos)?;
125 state.name_index += delta;
126 *pos += consumed;
127 return Ok(Segment::five(
128 generated_column,
129 state.source_index,
130 state.original_line,
131 state.original_column,
132 state.name_index,
133 ));
134 }
135
136 Ok(Segment::four(
137 generated_column,
138 state.source_index,
139 state.original_line,
140 state.original_column,
141 ))
142}