@@ -47,13 +47,111 @@ pub use vlq::{vlq_decode, vlq_decode_unsigned, vlq_encode, vlq_encode_unsigned};
4747
4848use std:: fmt;
4949
50- /// A single source map segment.
50+ /// A single source map segment stored inline (no heap allocation) .
5151///
5252/// Segments have 1, 4, or 5 fields:
5353/// - 1 field: `[generated_column]`
5454/// - 4 fields: `[generated_column, source_index, original_line, original_column]`
5555/// - 5 fields: `[generated_column, source_index, original_line, original_column, name_index]`
56- pub type Segment = Vec < i64 > ;
56+ ///
57+ /// Implements `Deref<Target=[i64]>` so indexing, `len()`, `is_empty()`, and
58+ /// iteration work identically to `Vec<i64>`.
59+ #[ derive( Debug , Clone , Copy ) ]
60+ pub struct Segment {
61+ data : [ i64 ; 5 ] ,
62+ len : u8 ,
63+ }
64+
65+ impl Segment {
66+ /// Create a 1-field segment (generated column only).
67+ #[ inline]
68+ pub fn one ( a : i64 ) -> Self {
69+ Self {
70+ data : [ a, 0 , 0 , 0 , 0 ] ,
71+ len : 1 ,
72+ }
73+ }
74+
75+ /// Create a 4-field segment (with source info, no name).
76+ #[ inline]
77+ pub fn four ( a : i64 , b : i64 , c : i64 , d : i64 ) -> Self {
78+ Self {
79+ data : [ a, b, c, d, 0 ] ,
80+ len : 4 ,
81+ }
82+ }
83+
84+ /// Create a 5-field segment (with source info and name).
85+ #[ inline]
86+ pub fn five ( a : i64 , b : i64 , c : i64 , d : i64 , e : i64 ) -> Self {
87+ Self {
88+ data : [ a, b, c, d, e] ,
89+ len : 5 ,
90+ }
91+ }
92+
93+ /// Convert to a `Vec<i64>` (for interop with APIs that expect `Vec`).
94+ pub fn to_vec ( & self ) -> Vec < i64 > {
95+ self . data [ ..self . len as usize ] . to_vec ( )
96+ }
97+ }
98+
99+ impl std:: ops:: Deref for Segment {
100+ type Target = [ i64 ] ;
101+
102+ #[ inline]
103+ fn deref ( & self ) -> & [ i64 ] {
104+ & self . data [ ..self . len as usize ]
105+ }
106+ }
107+
108+ impl < ' a > IntoIterator for & ' a Segment {
109+ type Item = & ' a i64 ;
110+ type IntoIter = std:: slice:: Iter < ' a , i64 > ;
111+
112+ #[ inline]
113+ fn into_iter ( self ) -> Self :: IntoIter {
114+ self . data [ ..self . len as usize ] . iter ( )
115+ }
116+ }
117+
118+ impl PartialEq for Segment {
119+ fn eq ( & self , other : & Self ) -> bool {
120+ * * self == * * other
121+ }
122+ }
123+
124+ impl Eq for Segment { }
125+
126+ impl PartialEq < Vec < i64 > > for Segment {
127+ fn eq ( & self , other : & Vec < i64 > ) -> bool {
128+ * * self == * * other
129+ }
130+ }
131+
132+ impl PartialEq < Segment > for Vec < i64 > {
133+ fn eq ( & self , other : & Segment ) -> bool {
134+ * * self == * * other
135+ }
136+ }
137+
138+ impl From < Vec < i64 > > for Segment {
139+ fn from ( v : Vec < i64 > ) -> Self {
140+ let mut data = [ 0i64 ; 5 ] ;
141+ let len = v. len ( ) . min ( 5 ) ;
142+ data[ ..len] . copy_from_slice ( & v[ ..len] ) ;
143+ Self { data, len : len as u8 }
144+ }
145+ }
146+
147+ impl From < & [ i64 ] > for Segment {
148+ fn from ( s : & [ i64 ] ) -> Self {
149+ let mut data = [ 0i64 ; 5 ] ;
150+ let len = s. len ( ) . min ( 5 ) ;
151+ data[ ..len] . copy_from_slice ( & s[ ..len] ) ;
152+ Self { data, len : len as u8 }
153+ }
154+ }
57155
58156/// A source map line is a list of segments.
59157pub type Line = Vec < Segment > ;
@@ -124,15 +222,15 @@ mod tests {
124222
125223 #[ test]
126224 fn roundtrip_large_values ( ) {
127- let mappings = vec ! [ vec![ vec! [ 1000_i64 , 50 , 999 , 500 , 100 ] ] ] ;
225+ let mappings = vec ! [ vec![ Segment :: five ( 1000 , 50 , 999 , 500 , 100 ) ] ] ;
128226 let encoded = encode ( & mappings) ;
129227 let decoded = decode ( & encoded) . unwrap ( ) ;
130228 assert_eq ! ( decoded, mappings) ;
131229 }
132230
133231 #[ test]
134232 fn roundtrip_negative_deltas ( ) {
135- let mappings = vec ! [ vec![ vec! [ 10_i64 , 0 , 10 , 10 ] , vec! [ 20 , 0 , 5 , 5 ] ] ] ;
233+ let mappings = vec ! [ vec![ Segment :: four ( 10 , 0 , 10 , 10 ) , Segment :: four ( 20 , 0 , 5 , 5 ) ] ] ;
136234 let encoded = encode ( & mappings) ;
137235 let decoded = decode ( & encoded) . unwrap ( ) ;
138236 assert_eq ! ( decoded, mappings) ;
@@ -259,20 +357,22 @@ mod tests {
259357 #[ test]
260358 fn encode_empty_segments_no_dangling_comma ( ) {
261359 // Empty segments should be skipped without producing dangling commas
262- let mappings = vec ! [ vec![ vec![ ] , vec![ 0 , 0 , 0 , 0 ] , vec![ ] , vec![ 2 , 0 , 0 , 1 ] ] ] ;
360+ let empty = Segment :: from ( & [ ] as & [ i64 ] ) ;
361+ let mappings = vec ! [ vec![ empty, Segment :: four( 0 , 0 , 0 , 0 ) , empty, Segment :: four( 2 , 0 , 0 , 1 ) ] ] ;
263362 let encoded = encode ( & mappings) ;
264363 assert ! (
265364 !encoded. contains( ",," ) ,
266365 "should not contain dangling commas"
267366 ) ;
268367 // Should encode as if empty segments don't exist
269- let expected = encode ( & vec ! [ vec![ vec! [ 0 , 0 , 0 , 0 ] , vec! [ 2 , 0 , 0 , 1 ] ] ] ) ;
368+ let expected = encode ( & vec ! [ vec![ Segment :: four ( 0 , 0 , 0 , 0 ) , Segment :: four ( 2 , 0 , 0 , 1 ) ] ] ) ;
270369 assert_eq ! ( encoded, expected) ;
271370 }
272371
273372 #[ test]
274373 fn encode_all_empty_segments ( ) {
275- let mappings = vec ! [ vec![ vec![ ] , vec![ ] , vec![ ] ] ] ;
374+ let empty = Segment :: from ( & [ ] as & [ i64 ] ) ;
375+ let mappings = vec ! [ vec![ empty, empty, empty] ] ;
276376 let encoded = encode ( & mappings) ;
277377 assert_eq ! ( encoded, "" ) ;
278378 }
@@ -288,13 +388,13 @@ mod tests {
288388 for line in 0 ..lines {
289389 let mut line_segments = Vec :: with_capacity ( segments_per_line) ;
290390 for seg in 0 ..segments_per_line {
291- line_segments. push ( vec ! [
391+ line_segments. push ( Segment :: five (
292392 ( seg * 10 ) as i64 , // generated column
293393 ( seg % 5 ) as i64 , // source index
294394 line as i64 , // original line
295395 ( seg * 5 ) as i64 , // original column
296396 ( seg % 3 ) as i64 , // name index
297- ] ) ;
397+ ) ) ;
298398 }
299399 mappings. push ( line_segments) ;
300400 }
@@ -328,25 +428,22 @@ mod tests {
328428 let mut line_segments = Vec :: new ( ) ;
329429 for seg in 0 ..8 {
330430 if seg % 4 == 0 {
331- // 1-field segment (generated-only)
332- line_segments. push ( vec ! [ ( seg * 10 ) as i64 ] ) ;
431+ line_segments. push ( Segment :: one ( ( seg * 10 ) as i64 ) ) ;
333432 } else if seg % 4 == 3 {
334- // 5-field segment (with name)
335- line_segments. push ( vec ! [
433+ line_segments. push ( Segment :: five (
336434 ( seg * 10 ) as i64 ,
337435 ( seg % 3 ) as i64 ,
338436 line as i64 ,
339437 ( seg * 5 ) as i64 ,
340438 ( seg % 2 ) as i64 ,
341- ] ) ;
439+ ) ) ;
342440 } else {
343- // 4-field segment
344- line_segments. push ( vec ! [
441+ line_segments. push ( Segment :: four (
345442 ( seg * 10 ) as i64 ,
346443 ( seg % 3 ) as i64 ,
347444 line as i64 ,
348445 ( seg * 5 ) as i64 ,
349- ] ) ;
446+ ) ) ;
350447 }
351448 }
352449 mappings. push ( line_segments) ;
@@ -411,7 +508,7 @@ mod tests {
411508
412509 #[ test]
413510 fn encode_single_segment_one_field ( ) {
414- let mappings = vec ! [ vec![ vec! [ 5_i64 ] ] ] ;
511+ let mappings = vec ! [ vec![ Segment :: one ( 5 ) ] ] ;
415512 let encoded = encode ( & mappings) ;
416513 let decoded = decode ( & encoded) . unwrap ( ) ;
417514 assert_eq ! ( decoded, mappings) ;
0 commit comments