@@ -143,6 +143,30 @@ impl QuoteOffsets {
143
143
}
144
144
}
145
145
146
+ pub trait IsString : AstToken {
147
+ fn quote_offsets ( & self ) -> Option < QuoteOffsets > {
148
+ let text = self . text ( ) ;
149
+ let offsets = QuoteOffsets :: new ( text) ?;
150
+ let o = self . syntax ( ) . text_range ( ) . start ( ) ;
151
+ let offsets = QuoteOffsets {
152
+ quotes : ( offsets. quotes . 0 + o, offsets. quotes . 1 + o) ,
153
+ contents : offsets. contents + o,
154
+ } ;
155
+ Some ( offsets)
156
+ }
157
+ fn text_range_between_quotes ( & self ) -> Option < TextRange > {
158
+ self . quote_offsets ( ) . map ( |it| it. contents )
159
+ }
160
+ fn open_quote_text_range ( & self ) -> Option < TextRange > {
161
+ self . quote_offsets ( ) . map ( |it| it. quotes . 0 )
162
+ }
163
+ fn close_quote_text_range ( & self ) -> Option < TextRange > {
164
+ self . quote_offsets ( ) . map ( |it| it. quotes . 1 )
165
+ }
166
+ }
167
+
168
+ impl IsString for ast:: String { }
169
+
146
170
impl ast:: String {
147
171
pub fn is_raw ( & self ) -> bool {
148
172
self . text ( ) . starts_with ( 'r' )
@@ -187,32 +211,49 @@ impl ast::String {
187
211
( false , false ) => Some ( Cow :: Owned ( buf) ) ,
188
212
}
189
213
}
190
-
191
- pub fn quote_offsets ( & self ) -> Option < QuoteOffsets > {
192
- let text = self . text ( ) ;
193
- let offsets = QuoteOffsets :: new ( text) ?;
194
- let o = self . syntax ( ) . text_range ( ) . start ( ) ;
195
- let offsets = QuoteOffsets {
196
- quotes : ( offsets. quotes . 0 + o, offsets. quotes . 1 + o) ,
197
- contents : offsets. contents + o,
198
- } ;
199
- Some ( offsets)
200
- }
201
- pub fn text_range_between_quotes ( & self ) -> Option < TextRange > {
202
- self . quote_offsets ( ) . map ( |it| it. contents )
203
- }
204
- pub fn open_quote_text_range ( & self ) -> Option < TextRange > {
205
- self . quote_offsets ( ) . map ( |it| it. quotes . 0 )
206
- }
207
- pub fn close_quote_text_range ( & self ) -> Option < TextRange > {
208
- self . quote_offsets ( ) . map ( |it| it. quotes . 1 )
209
- }
210
214
}
211
215
216
+ impl IsString for ast:: ByteString { }
217
+
212
218
impl ast:: ByteString {
213
219
pub fn is_raw ( & self ) -> bool {
214
220
self . text ( ) . starts_with ( "br" )
215
221
}
222
+
223
+ pub fn value ( & self ) -> Option < Cow < ' _ , [ u8 ] > > {
224
+ if self . is_raw ( ) {
225
+ let text = self . text ( ) ;
226
+ let text =
227
+ & text[ self . text_range_between_quotes ( ) ? - self . syntax ( ) . text_range ( ) . start ( ) ] ;
228
+ return Some ( Cow :: Borrowed ( text. as_bytes ( ) ) ) ;
229
+ }
230
+
231
+ let text = self . text ( ) ;
232
+ let text = & text[ self . text_range_between_quotes ( ) ? - self . syntax ( ) . text_range ( ) . start ( ) ] ;
233
+
234
+ let mut buf: Vec < u8 > = Vec :: new ( ) ;
235
+ let mut text_iter = text. chars ( ) ;
236
+ let mut has_error = false ;
237
+ unescape_literal ( text, Mode :: ByteStr , & mut |char_range, unescaped_char| match (
238
+ unescaped_char,
239
+ buf. capacity ( ) == 0 ,
240
+ ) {
241
+ ( Ok ( c) , false ) => buf. push ( c as u8 ) ,
242
+ ( Ok ( c) , true ) if char_range. len ( ) == 1 && Some ( c) == text_iter. next ( ) => ( ) ,
243
+ ( Ok ( c) , true ) => {
244
+ buf. reserve_exact ( text. len ( ) ) ;
245
+ buf. extend_from_slice ( & text[ ..char_range. start ] . as_bytes ( ) ) ;
246
+ buf. push ( c as u8 ) ;
247
+ }
248
+ ( Err ( _) , _) => has_error = true ,
249
+ } ) ;
250
+
251
+ match ( has_error, buf. capacity ( ) == 0 ) {
252
+ ( true , _) => None ,
253
+ ( false , true ) => Some ( Cow :: Borrowed ( text. as_bytes ( ) ) ) ,
254
+ ( false , false ) => Some ( Cow :: Owned ( buf) ) ,
255
+ }
256
+ }
216
257
}
217
258
218
259
#[ derive( Debug ) ]
0 commit comments