@@ -29,7 +29,7 @@ internal struct JSONParser {
29
29
}
30
30
}
31
31
#endif
32
-
32
+
33
33
// ensure only white space is remaining
34
34
var whitespace = 0
35
35
while let next = reader. peek ( offset: whitespace) {
@@ -41,7 +41,7 @@ internal struct JSONParser {
41
41
throw JSONError . unexpectedCharacter ( ascii: next, characterIndex: reader. readerIndex + whitespace)
42
42
}
43
43
}
44
-
44
+
45
45
return value
46
46
}
47
47
@@ -107,15 +107,15 @@ internal struct JSONParser {
107
107
default :
108
108
break
109
109
}
110
-
110
+
111
111
var array = [ JSONValue] ( )
112
112
array. reserveCapacity ( 10 )
113
-
113
+
114
114
// parse values
115
115
while true {
116
116
let value = try parseValue ( )
117
117
array. append ( value)
118
-
118
+
119
119
// consume the whitespace after the value before the comma
120
120
let ascii = try reader. consumeWhitespace ( )
121
121
switch ascii {
@@ -161,7 +161,7 @@ internal struct JSONParser {
161
161
default :
162
162
break
163
163
}
164
-
164
+
165
165
var object = [ String: JSONValue] ( )
166
166
object. reserveCapacity ( 20 )
167
167
@@ -174,7 +174,7 @@ internal struct JSONParser {
174
174
reader. moveReaderIndex ( forwardBy: 1 )
175
175
try reader. consumeWhitespace ( )
176
176
object [ key] = try self . parseValue ( )
177
-
177
+
178
178
let commaOrBrace = try reader. consumeWhitespace ( )
179
179
switch commaOrBrace {
180
180
case . _closebrace:
@@ -196,26 +196,26 @@ internal struct JSONParser {
196
196
}
197
197
198
198
extension JSONParser {
199
-
199
+
200
200
struct DocumentReader {
201
201
let array : [ UInt8 ]
202
202
203
203
private( set) var readerIndex : Int = 0
204
-
204
+
205
205
private var readableBytes : Int {
206
206
self . array. endIndex - self . readerIndex
207
207
}
208
-
208
+
209
209
var isEOF : Bool {
210
210
self . readerIndex >= self . array. endIndex
211
211
}
212
-
212
+
213
213
214
214
init ( array: [ UInt8 ] ) {
215
215
self . array = array
216
216
}
217
217
218
- subscript( bounds : Range < Int > ) -> ArraySlice < UInt8 > {
218
+ subscript< R : RangeExpression < Int > > ( bounds : R ) -> ArraySlice < UInt8 > {
219
219
self . array [ bounds]
220
220
}
221
221
@@ -234,14 +234,14 @@ extension JSONParser {
234
234
guard self . readerIndex + offset < self . array. endIndex else {
235
235
return nil
236
236
}
237
-
237
+
238
238
return self . array [ self . readerIndex + offset]
239
239
}
240
-
240
+
241
241
mutating func moveReaderIndex( forwardBy offset: Int ) {
242
242
self . readerIndex += offset
243
243
}
244
-
244
+
245
245
@discardableResult
246
246
mutating func consumeWhitespace( ) throws -> UInt8 {
247
247
var whitespace = 0
@@ -255,18 +255,18 @@ extension JSONParser {
255
255
return ascii
256
256
}
257
257
}
258
-
258
+
259
259
throw JSONError . unexpectedEndOfFile
260
260
}
261
-
261
+
262
262
mutating func readString( ) throws -> String {
263
263
try self . readUTF8StringTillNextUnescapedQuote ( )
264
264
}
265
-
265
+
266
266
mutating func readNumber( ) throws -> String {
267
267
try self . parseNumber ( )
268
268
}
269
-
269
+
270
270
mutating func readBool( ) throws -> Bool {
271
271
switch self . read ( ) {
272
272
case UInt8 ( ascii: " t " ) :
@@ -314,11 +314,11 @@ extension JSONParser {
314
314
throw JSONError . unexpectedCharacter ( ascii: self . peek ( offset: - 1 ) !, characterIndex: self . readerIndex - 1 )
315
315
}
316
316
}
317
-
317
+
318
318
// MARK: - Private Methods -
319
319
320
320
// MARK: String
321
-
321
+
322
322
enum EscapedSequenceError : Swift . Error {
323
323
case expectedLowSurrogateUTF8SequenceAfterHighSurrogate( index: Int )
324
324
case unexpectedEscapedCharacter( ascii: UInt8 , index: Int )
@@ -339,10 +339,10 @@ extension JSONParser {
339
339
self . moveReaderIndex ( forwardBy: copy + 1 )
340
340
guard var result = output else {
341
341
// if we don't have an output string we create a new string
342
- return String ( decoding : self [ stringStartIndex ..< stringStartIndex + copy] , as : Unicode . UTF8 . self )
342
+ return try makeString ( at : stringStartIndex ..< stringStartIndex + copy)
343
343
}
344
344
// if we have an output string we append
345
- result += String ( decoding : self [ stringStartIndex ..< stringStartIndex + copy] , as : Unicode . UTF8 . self )
345
+ result += try makeString ( at : stringStartIndex ..< stringStartIndex + copy)
346
346
return result
347
347
348
348
case 0 ... 31 :
@@ -352,17 +352,17 @@ extension JSONParser {
352
352
// through U+001F).
353
353
var string = output ?? " "
354
354
let errorIndex = self . readerIndex + copy
355
- string += self . makeStringFast ( self . array [ stringStartIndex ... errorIndex] )
355
+ string += try makeString ( at : stringStartIndex ... errorIndex)
356
356
throw JSONError . unescapedControlCharacterInString ( ascii: byte, in: string, index: errorIndex)
357
357
358
358
case UInt8 ( ascii: " \\ " ) :
359
359
self . moveReaderIndex ( forwardBy: copy)
360
360
if output != nil {
361
- output! += self . makeStringFast ( self . array [ stringStartIndex ..< stringStartIndex + copy] )
361
+ output! += try makeString ( at : stringStartIndex ..< stringStartIndex + copy)
362
362
} else {
363
- output = self . makeStringFast ( self . array [ stringStartIndex ..< stringStartIndex + copy] )
363
+ output = try makeString ( at : stringStartIndex ..< stringStartIndex + copy)
364
364
}
365
-
365
+
366
366
let escapedStartIndex = self . readerIndex
367
367
368
368
do {
@@ -371,13 +371,13 @@ extension JSONParser {
371
371
stringStartIndex = self . readerIndex
372
372
copy = 0
373
373
} catch EscapedSequenceError . unexpectedEscapedCharacter( let ascii, let failureIndex) {
374
- output! += makeStringFast ( array [ escapedStartIndex ..< self . readerIndex] )
374
+ output! += try makeString ( at : escapedStartIndex ..< self . readerIndex)
375
375
throw JSONError . unexpectedEscapedCharacter ( ascii: ascii, in: output!, index: failureIndex)
376
376
} catch EscapedSequenceError . expectedLowSurrogateUTF8SequenceAfterHighSurrogate( let failureIndex) {
377
- output! += makeStringFast ( array [ escapedStartIndex ..< self . readerIndex] )
377
+ output! += try makeString ( at : escapedStartIndex ..< self . readerIndex)
378
378
throw JSONError . expectedLowSurrogateUTF8SequenceAfterHighSurrogate ( in: output!, index: failureIndex)
379
379
} catch EscapedSequenceError . couldNotCreateUnicodeScalarFromUInt32( let failureIndex, let unicodeScalarValue) {
380
- output! += makeStringFast ( array [ escapedStartIndex ..< self . readerIndex] )
380
+ output! += try makeString ( at : escapedStartIndex ..< self . readerIndex)
381
381
throw JSONError . couldNotCreateUnicodeScalarFromUInt32 (
382
382
in: output!, index: failureIndex, unicodeScalarValue: unicodeScalarValue
383
383
)
@@ -392,15 +392,12 @@ extension JSONParser {
392
392
throw JSONError . unexpectedEndOfFile
393
393
}
394
394
395
- // can be removed as soon https://bugs.swift.org/browse/SR-12126 and
396
- // https://bugs.swift.org/browse/SR-12125 has landed.
397
- // Thanks @weissi for making my code fast!
398
- private func makeStringFast< Bytes: Collection > ( _ bytes: Bytes ) -> String where Bytes. Element == UInt8 {
399
- if let string = bytes. withContiguousStorageIfAvailable ( { String ( decoding: $0, as: Unicode . UTF8. self) } ) {
400
- return string
401
- } else {
402
- return String ( decoding: bytes, as: Unicode . UTF8. self)
395
+ private func makeString< R: RangeExpression < Int > > ( at range: R ) throws -> String {
396
+ let raw = array [ range]
397
+ guard let str = String ( bytes: raw, encoding: . utf8) else {
398
+ throw JSONError . invalidUTF8Sequence ( Data ( raw) , characterIndex: range. relative ( to: array) . lowerBound)
403
399
}
400
+ return str
404
401
}
405
402
406
403
private mutating func parseEscapeSequence( ) throws -> String {
@@ -514,9 +511,9 @@ extension JSONParser {
514
511
return nil
515
512
}
516
513
}
517
-
514
+
518
515
// MARK: Numbers
519
-
516
+
520
517
private enum ControlCharacter {
521
518
case operand
522
519
case decimalPoint
@@ -550,7 +547,7 @@ extension JSONParser {
550
547
}
551
548
552
549
var numberchars = 1
553
-
550
+
554
551
// parse everything else
555
552
while let byte = self . peek ( offset: numberchars) {
556
553
switch byte {
@@ -606,7 +603,7 @@ extension JSONParser {
606
603
let numberStartIndex = self . readerIndex
607
604
self . moveReaderIndex ( forwardBy: numberchars)
608
605
609
- return self . makeStringFast ( self [ numberStartIndex ..< self . readerIndex] )
606
+ return String ( decoding : self [ numberStartIndex ..< self . readerIndex] , as : Unicode . UTF8 . self )
610
607
default :
611
608
throw JSONError . unexpectedCharacter ( ascii: byte, characterIndex: readerIndex + numberchars)
612
609
}
@@ -623,32 +620,32 @@ extension JSONParser {
623
620
}
624
621
625
622
extension UInt8 {
626
-
623
+
627
624
internal static let _space = UInt8 ( ascii: " " )
628
625
internal static let _return = UInt8 ( ascii: " \r " )
629
626
internal static let _newline = UInt8 ( ascii: " \n " )
630
627
internal static let _tab = UInt8 ( ascii: " \t " )
631
-
628
+
632
629
internal static let _colon = UInt8 ( ascii: " : " )
633
630
internal static let _comma = UInt8 ( ascii: " , " )
634
-
631
+
635
632
internal static let _openbrace = UInt8 ( ascii: " { " )
636
633
internal static let _closebrace = UInt8 ( ascii: " } " )
637
-
634
+
638
635
internal static let _openbracket = UInt8 ( ascii: " [ " )
639
636
internal static let _closebracket = UInt8 ( ascii: " ] " )
640
-
637
+
641
638
internal static let _quote = UInt8 ( ascii: " \" " )
642
639
internal static let _backslash = UInt8 ( ascii: " \\ " )
643
-
640
+
644
641
}
645
642
646
643
extension Array where Element == UInt8 {
647
-
644
+
648
645
internal static let _true = [ UInt8 ( ascii: " t " ) , UInt8 ( ascii: " r " ) , UInt8 ( ascii: " u " ) , UInt8 ( ascii: " e " ) ]
649
646
internal static let _false = [ UInt8 ( ascii: " f " ) , UInt8 ( ascii: " a " ) , UInt8 ( ascii: " l " ) , UInt8 ( ascii: " s " ) , UInt8 ( ascii: " e " ) ]
650
647
internal static let _null = [ UInt8 ( ascii: " n " ) , UInt8 ( ascii: " u " ) , UInt8 ( ascii: " l " ) , UInt8 ( ascii: " l " ) ]
651
-
648
+
652
649
}
653
650
654
651
enum JSONError : Swift . Error , Equatable {
@@ -664,4 +661,5 @@ enum JSONError: Swift.Error, Equatable {
664
661
case numberWithLeadingZero( index: Int )
665
662
case numberIsNotRepresentableInSwift( parsed: String )
666
663
case singleFragmentFoundButNotAllowed
664
+ case invalidUTF8Sequence( Data , characterIndex: Int )
667
665
}
0 commit comments