@@ -7,14 +7,14 @@ pub struct MagicStringOptions {
7
7
pub filename : Option < String > ,
8
8
}
9
9
10
- #[ derive( Default ) ]
11
10
pub struct MagicString < ' s > {
12
11
pub filename : Option < String > ,
13
-
12
+
14
13
source : CowStr < ' s > ,
15
14
source_len : u32 ,
16
15
chunks : ChunkVec < ' s > ,
17
- first_chunk_idx : Option < ChunkIdx > ,
16
+ first_chunk_idx : ChunkIdx ,
17
+ last_chunk_idx : ChunkIdx ,
18
18
chunk_by_start : FxHashMap < u32 , ChunkIdx > ,
19
19
chunk_by_end : FxHashMap < u32 , ChunkIdx > ,
20
20
}
@@ -29,26 +29,86 @@ impl<'s> MagicString<'s> {
29
29
pub fn with_options ( source : impl Into < CowStr < ' s > > , options : MagicStringOptions ) -> Self {
30
30
let source = source. into ( ) ;
31
31
let source_len: u32 = source. len ( ) . try_into ( ) . expect ( "source is too big" ) ;
32
+ let initial_chunk = Chunk :: new ( Span ( 0 , source_len) ) ;
33
+ let mut chunks = ChunkVec :: with_capacity ( 1 ) ;
34
+ let initial_chunk_idx = chunks. push ( initial_chunk) ;
32
35
let mut magic_string = Self {
33
36
source,
34
37
source_len,
35
- ..Default :: default ( )
38
+ first_chunk_idx : initial_chunk_idx,
39
+ last_chunk_idx : initial_chunk_idx,
40
+ chunks,
41
+ chunk_by_start : Default :: default ( ) ,
42
+ chunk_by_end : Default :: default ( ) ,
43
+ // setup options
44
+ filename : options. filename ,
36
45
} ;
37
- magic_string. split_at ( source_len) ;
38
- magic_string. first_chunk_idx = Some ( ChunkIdx :: from_raw ( 0 ) ) ;
39
46
40
- magic_string. filename = options. filename ;
47
+ magic_string. chunk_by_start . insert ( 0 , initial_chunk_idx) ;
48
+ magic_string
49
+ . chunk_by_end
50
+ . insert ( source_len, initial_chunk_idx) ;
41
51
42
52
magic_string
43
53
}
44
54
45
55
pub fn append ( & mut self , source : impl Into < CowStr < ' s > > ) -> & mut Self {
46
- self . last_chunk_mut ( ) . append ( source. into ( ) ) ;
56
+ self . last_chunk_mut ( ) . append_outro ( source. into ( ) ) ;
57
+ self
58
+ }
59
+
60
+ /// # Example
61
+ ///```rust
62
+ /// use string_wizard::MagicString;
63
+ /// let mut s = MagicString::new("01234");
64
+ /// s.append_left(2, "a");
65
+ /// s.append_left(2, "b");
66
+ /// assert_eq!(s.to_string(), "01ab234")
67
+ ///```
68
+ pub fn append_left ( & mut self , text_index : u32 , source : impl Into < CowStr < ' s > > ) -> & mut Self {
69
+ self . split_at ( text_index) ;
70
+ let idx = self . chunk_by_end . get ( & text_index) . unwrap ( ) ;
71
+ let chunk = & mut self . chunks [ * idx] ;
72
+ chunk. append_outro ( source. into ( ) ) ;
73
+ self
74
+ }
75
+
76
+ /// # Example
77
+ /// ```rust
78
+ /// use string_wizard::MagicString;
79
+ /// let mut s = MagicString::new("01234");
80
+ /// s.append_right(2, "A");
81
+ /// s.append_right(2, "B");
82
+ /// s.append_left(2, "a");
83
+ /// s.append_left(2, "b");
84
+ /// assert_eq!(s.to_string(), "01abAB234")
85
+ ///```
86
+ pub fn append_right ( & mut self , text_index : u32 , source : impl Into < CowStr < ' s > > ) -> & mut Self {
87
+ self . split_at ( text_index) ;
88
+ let idx = self . chunk_by_start . get ( & text_index) . unwrap ( ) ;
89
+ let chunk = & mut self . chunks [ * idx] ;
90
+ chunk. append_intro ( source. into ( ) ) ;
47
91
self
48
92
}
49
93
50
94
pub fn prepend ( & mut self , source : impl Into < CowStr < ' s > > ) -> & mut Self {
51
- self . first_chunk_mut ( ) . prepend ( source. into ( ) ) ;
95
+ self . first_chunk_mut ( ) . prepend_intro ( source. into ( ) ) ;
96
+ self
97
+ }
98
+
99
+ pub fn prepend_left ( & mut self , text_index : u32 , content : impl Into < CowStr < ' s > > ) -> & mut Self {
100
+ self . split_at ( text_index) ;
101
+ let idx = self . chunk_by_end . get ( & text_index) . unwrap ( ) ;
102
+ let chunk = & mut self . chunks [ * idx] ;
103
+ chunk. prepend_outro ( content. into ( ) ) ;
104
+ self
105
+ }
106
+
107
+ pub fn prepend_right ( & mut self , text_index : u32 , content : impl Into < CowStr < ' s > > ) -> & mut Self {
108
+ self . split_at ( text_index) ;
109
+ let idx = self . chunk_by_start . get ( & text_index) . unwrap ( ) ;
110
+ let chunk = & mut self . chunks [ * idx] ;
111
+ chunk. prepend_intro ( content. into ( ) ) ;
52
112
self
53
113
}
54
114
@@ -67,7 +127,7 @@ impl<'s> MagicString<'s> {
67
127
68
128
fn iter_chunks ( & self ) -> impl Iterator < Item = & Chunk > {
69
129
ChunkIter {
70
- next : self . first_chunk_idx ,
130
+ next : Some ( self . first_chunk_idx ) ,
71
131
chunks : & self . chunks ,
72
132
}
73
133
}
@@ -76,39 +136,62 @@ impl<'s> MagicString<'s> {
76
136
self . iter_chunks ( ) . flat_map ( |c| c. fragments ( & self . source ) )
77
137
}
78
138
79
- /// a b c d e f g
80
- /// 0 1 2 3 4 5 6
81
- /// split_at(3)
82
- /// a b c d e f g
83
- /// [0 1 2][3 4 5 6]
84
- fn split_at ( & mut self , idx : u32 ) {
85
- let source_len = self . source_len ;
86
- debug_assert ! ( idx <= source_len) ;
87
- if self . chunks . is_empty ( ) {
88
- let prev_span = Span ( 0 , idx) ;
89
- self . create_chunk ( prev_span) ;
90
- if idx < source_len {
91
- self . create_chunk ( Span ( idx, source_len) ) ;
92
- }
93
- } else {
139
+ /// For input
140
+ /// "abcdefg"
141
+ /// 0123456
142
+ ///
143
+ /// Chunk{span: (0, 7)} => "abcdefg"
144
+ ///
145
+ /// split_at(3) would create
146
+ ///
147
+ /// Chunk{span: (0, 3)} => "abc"
148
+ /// Chunk{span: (3, 7)} => "defg"
149
+ fn split_at ( & mut self , text_index : u32 ) {
150
+ debug_assert ! ( text_index <= self . source_len) ;
151
+
152
+ if self . chunk_by_start . contains_key ( & text_index)
153
+ || self . chunk_by_end . contains_key ( & text_index)
154
+ {
155
+ return ;
94
156
}
95
- }
96
157
97
- fn create_chunk ( & mut self , span : Span ) -> ChunkIdx {
98
- let idx = self . chunks . push ( Chunk :: new ( span) ) ;
99
- self . chunk_by_start . insert ( span. start ( ) , idx) ;
100
- self . chunk_by_end . insert ( span. end ( ) , idx) ;
101
- idx
158
+ let mut target = & self . chunks [ self . first_chunk_idx ] ;
159
+ let mut target_idx = self . first_chunk_idx ;
160
+
161
+ let search_right = text_index > target. end ( ) ;
162
+
163
+ while !target. contains ( text_index) {
164
+ let next_idx = if search_right {
165
+ self . chunk_by_start . get ( & target. end ( ) ) . unwrap ( )
166
+ } else {
167
+ self . chunk_by_end . get ( & target. start ( ) ) . unwrap ( )
168
+ } ;
169
+ target = & self . chunks [ * next_idx] ;
170
+ target_idx = * next_idx;
171
+ }
172
+
173
+ let chunk_contains_index = & mut self . chunks [ target_idx] ;
174
+
175
+ let new_chunk = chunk_contains_index. split ( text_index) ;
176
+ self . chunk_by_end . insert ( text_index, target_idx) ;
177
+ let new_chunk_end = new_chunk. end ( ) ;
178
+ let new_chunk_idx = self . chunks . push ( new_chunk) ;
179
+ self . chunk_by_start . insert ( text_index, new_chunk_idx) ;
180
+ self . chunk_by_end . insert ( new_chunk_end, new_chunk_idx) ;
181
+
182
+ let chunk_contains_index = & mut self . chunks [ target_idx] ;
183
+ if target_idx == self . last_chunk_idx {
184
+ self . last_chunk_idx = new_chunk_idx
185
+ }
186
+ chunk_contains_index. next = Some ( new_chunk_idx) ;
102
187
}
103
188
104
189
fn last_chunk_mut ( & mut self ) -> & mut Chunk < ' s > {
105
- let idx = self . chunk_by_end . get ( & ( self . source_len ) ) . unwrap ( ) ;
106
- & mut self . chunks [ * idx]
190
+ & mut self . chunks [ self . last_chunk_idx ]
107
191
}
108
192
109
193
fn first_chunk_mut ( & mut self ) -> & mut Chunk < ' s > {
110
- let idx = self . chunk_by_start . get ( & 0 ) . unwrap ( ) ;
111
- & mut self . chunks [ * idx]
194
+ & mut self . chunks [ self . first_chunk_idx ]
112
195
}
113
196
}
114
197
0 commit comments