Skip to content

Commit 80f8bb7

Browse files
authored
Merge pull request swiftlang#497 from swiftwasm/main
[pull] swiftwasm from main
2 parents fb7eada + cd98893 commit 80f8bb7

File tree

4 files changed

+299
-19
lines changed

4 files changed

+299
-19
lines changed

Sources/Foundation/JSONDecoder.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -454,30 +454,30 @@ extension JSONDecoderImpl: Decoder {
454454
return nsNumber.uint8Value as! T
455455
}
456456
if type == Int8.self, NSNumber(value: nsNumber.int8Value) == nsNumber {
457-
return nsNumber.uint8Value as! T
457+
return nsNumber.int8Value as! T
458458
}
459459
if type == UInt16.self, NSNumber(value: nsNumber.uint16Value) == nsNumber {
460460
return nsNumber.uint16Value as! T
461461
}
462462
if type == Int16.self, NSNumber(value: nsNumber.int16Value) == nsNumber {
463-
return nsNumber.uint16Value as! T
463+
return nsNumber.int16Value as! T
464464
}
465465
if type == UInt32.self, NSNumber(value: nsNumber.uint32Value) == nsNumber {
466466
return nsNumber.uint32Value as! T
467467
}
468468
if type == Int32.self, NSNumber(value: nsNumber.int32Value) == nsNumber {
469-
return nsNumber.uint32Value as! T
469+
return nsNumber.int32Value as! T
470470
}
471471
if type == UInt64.self, NSNumber(value: nsNumber.uint64Value) == nsNumber {
472472
return nsNumber.uint64Value as! T
473473
}
474474
if type == Int64.self, NSNumber(value: nsNumber.int64Value) == nsNumber {
475-
return nsNumber.uint64Value as! T
475+
return nsNumber.int64Value as! T
476476
}
477477
if type == UInt.self, NSNumber(value: nsNumber.uintValue) == nsNumber {
478478
return nsNumber.uintValue as! T
479479
}
480-
if type == Int.self, NSNumber(value: nsNumber.uintValue) == nsNumber {
480+
if type == Int.self, NSNumber(value: nsNumber.intValue) == nsNumber {
481481
return nsNumber.intValue as! T
482482
}
483483
}

Sources/Foundation/NSStringAPI.swift

Lines changed: 120 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -20,7 +20,7 @@
2020
// This file is shared between two projects:
2121
//
2222
// 1. https://github.com/apple/swift/tree/master/stdlib/public/Darwin/Foundation
23-
// 2. https://github.com/apple/swift-corelibs-foundation/tree/master/Foundation
23+
// 2. https://github.com/apple/swift-corelibs-foundation/tree/main/Foundation
2424
//
2525
// If you change this file, you must update it in both places.
2626

@@ -176,7 +176,7 @@ extension String {
176176
// + (instancetype)stringWithUTF8String:(const char *)bytes
177177

178178
/// Creates a string by copying the data from a given
179-
/// C array of UTF8-encoded bytes.
179+
/// null-terminated C array of UTF8-encoded bytes.
180180
public init?(utf8String bytes: UnsafePointer<CChar>) {
181181
if let str = String(validatingUTF8: bytes) {
182182
self = str
@@ -188,6 +188,54 @@ extension String {
188188
return nil
189189
}
190190
}
191+
192+
/// Creates a string by copying the data from a given
193+
/// null-terminated array of UTF8-encoded bytes.
194+
@_alwaysEmitIntoClient
195+
public init?(utf8String bytes: [CChar]) {
196+
// the stdlib's validatingUTF8 [CChar] overload checks for null termination.
197+
if let str = String(validatingUTF8: bytes) {
198+
self = str
199+
return
200+
}
201+
guard let nullPosition = bytes.firstIndex(of: 0) else {
202+
fatalError(
203+
"input of String.init(utf8String:) must be null-terminated"
204+
)
205+
}
206+
let ns = bytes.withUnsafeBytes {
207+
NSString(bytes: $0.baseAddress!,
208+
length: nullPosition,
209+
encoding: Encoding.utf8.rawValue)
210+
}
211+
guard let ns = ns else {
212+
return nil
213+
}
214+
self = String._unconditionallyBridgeFromObjectiveC(ns)
215+
}
216+
217+
@_alwaysEmitIntoClient
218+
@available(*, deprecated, message: "Use a copy of the String argument")
219+
public init?(utf8String bytes: String) {
220+
var decoded = bytes
221+
decoded.makeContiguousUTF8()
222+
if let null = decoded.firstIndex(of: "\0") {
223+
decoded = String(decoded[..<null])
224+
}
225+
self = decoded
226+
}
227+
228+
@_alwaysEmitIntoClient
229+
@available(*, deprecated, message: "Use String(_ scalar: Unicode.Scalar)")
230+
public init?(utf8String bytes: inout CChar) {
231+
// a byte interpreted as a buffer is valid only if the value is zero.
232+
guard bytes == 0 else {
233+
fatalError(
234+
"input of String.init(utf8String:) must be null-terminated"
235+
)
236+
}
237+
self = ""
238+
}
191239
}
192240

193241
extension String {
@@ -371,15 +419,16 @@ extension String {
371419
// initWithCString:(const char *)nullTerminatedCString
372420
// encoding:(NSStringEncoding)encoding
373421

374-
/// Produces a string containing the bytes in a given C array,
375-
/// interpreted according to a given encoding.
376-
public init?(
377-
cString: UnsafePointer<CChar>,
378-
encoding enc: Encoding
379-
) {
380-
if enc == .utf8, let str = String(validatingUTF8: cString) {
381-
self = str
382-
return
422+
/// Produces a string by copying the null-terminated bytes
423+
/// in a given C array, interpreted according to a given encoding.
424+
public init?(cString: UnsafePointer<CChar>, encoding enc: Encoding) {
425+
if enc == .utf8 || enc == .ascii {
426+
if let str = String(validatingUTF8: cString) {
427+
if enc == .utf8 || str._guts._isContiguousASCII {
428+
self = str
429+
return
430+
}
431+
}
383432
}
384433
if let ns = NSString(cString: cString, encoding: enc.rawValue) {
385434
self = String._unconditionallyBridgeFromObjectiveC(ns)
@@ -388,6 +437,64 @@ extension String {
388437
}
389438
}
390439

440+
/// Produces a string by copying the null-terminated bytes
441+
/// in a given array, interpreted according to a given encoding.
442+
@_alwaysEmitIntoClient
443+
public init?(cString: [CChar], encoding enc: Encoding) {
444+
if enc == .utf8 || enc == .ascii {
445+
// the stdlib's validatingUTF8 [CChar] overload checks for null termination.
446+
if let str = String(validatingUTF8: cString) {
447+
if enc == .utf8 || str._guts._isContiguousASCII {
448+
self = str
449+
return
450+
}
451+
}
452+
}
453+
guard let nullPosition = cString.firstIndex(of: 0) else {
454+
fatalError(
455+
"input of String.init(cString:encoding:) must be null-terminated"
456+
)
457+
}
458+
let ns = cString.withUnsafeBytes {
459+
NSString(bytes: $0.baseAddress!,
460+
length: nullPosition,
461+
encoding: enc.rawValue)
462+
}
463+
guard let ns = ns else {
464+
return nil
465+
}
466+
self = String._unconditionallyBridgeFromObjectiveC(ns)
467+
}
468+
469+
@_alwaysEmitIntoClient
470+
@available(*, deprecated, message: "Use a copy of the String argument")
471+
public init?(cString: String, encoding enc: Encoding) {
472+
if enc == .utf8 || enc == .ascii {
473+
var decoded = cString
474+
decoded.makeContiguousUTF8()
475+
if let null = decoded.firstIndex(of: "\0") {
476+
decoded = String(decoded[..<null])
477+
}
478+
if enc == .utf8 || decoded.utf8.allSatisfy({ $0 < 128 }) {
479+
self = decoded
480+
return
481+
}
482+
}
483+
return nil
484+
}
485+
486+
@_alwaysEmitIntoClient
487+
@available(*, deprecated, message: "Use String(_ scalar: Unicode.Scalar)")
488+
public init?(cString: inout CChar, encoding enc: Encoding) {
489+
// a byte interpreted as a buffer is valid only if the value is zero.
490+
guard cString == 0 else {
491+
fatalError(
492+
"input of String.init(cString:encoding:) must be null-terminated"
493+
)
494+
}
495+
self = ""
496+
}
497+
391498
// FIXME: handle optional locale with default arguments
392499

393500
// - (instancetype)
@@ -465,7 +572,7 @@ extension String {
465572
}
466573
}
467574

468-
extension StringProtocol where Index == String.Index {
575+
extension StringProtocol {
469576
//===--- Bridging Helpers -----------------------------------------------===//
470577
//===--------------------------------------------------------------------===//
471578

Tests/Foundation/Tests/TestJSONEncoder.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,66 @@ class TestJSONEncoder : XCTestCase {
656656
}
657657
}
658658

659+
func test_encodeDecodeNumericTypesBaseline() throws {
660+
struct NumericTypesStruct: Codable, Equatable {
661+
let int8Value: Int8
662+
let uint8Value: UInt8
663+
let int16Value: Int16
664+
let uint16Value: UInt16
665+
let int32Value: Int32
666+
let uint32Value: UInt32
667+
let int64Value: Int64
668+
let intValue: Int
669+
let uintValue: UInt
670+
let uint64Value: UInt64
671+
let floatValue: Float
672+
let doubleValue: Double
673+
let decimalValue: Decimal
674+
}
675+
676+
let source = NumericTypesStruct(
677+
int8Value: -12,
678+
uint8Value: 34,
679+
int16Value: -5678,
680+
uint16Value: 9011,
681+
int32Value: -12141516,
682+
uint32Value: 17181920,
683+
int64Value: -21222324252627,
684+
intValue: -2829303132,
685+
uintValue: 33343536,
686+
uint64Value: 373839404142,
687+
floatValue: 1.234,
688+
doubleValue: 5.101520,
689+
decimalValue: Decimal(10))
690+
691+
let data = try JSONEncoder().encode(source)
692+
let destination = try JSONDecoder().decode(NumericTypesStruct.self, from: data)
693+
XCTAssertEqual(source, destination)
694+
695+
// Ensure that if a value is expressed as a floating point number, it casts correctly into the underlying type.
696+
697+
let json = """
698+
{
699+
"int8Value": -12.0,
700+
"uint8Value": 34.0,
701+
"int16Value": -5678.0,
702+
"uint16Value": 9011.0,
703+
"int32Value": -12141516.0,
704+
"uint32Value": 17181920.0,
705+
"int64Value": -21222324252627.0,
706+
"intValue": -2829303132.0,
707+
"uintValue": 33343536.0,
708+
"uint64Value": 373839404142.0,
709+
"floatValue": 1.234,
710+
"doubleValue": 5.101520,
711+
"decimalValue": 10.0
712+
}
713+
"""
714+
715+
let destination2 = try JSONDecoder().decode(NumericTypesStruct.self, from: Data(json.utf8))
716+
XCTAssertEqual(source, destination2)
717+
}
718+
659719
func test_numericLimits() {
660720
struct DataStruct: Codable {
661721
let int8Value: Int8?
@@ -1479,6 +1539,7 @@ extension TestJSONEncoder {
14791539
("test_encodingCustomDataEmpty", test_encodingCustomDataEmpty),
14801540
("test_encodingNonConformingFloats", test_encodingNonConformingFloats),
14811541
("test_encodingNonConformingFloatStrings", test_encodingNonConformingFloatStrings),
1542+
("test_encodeDecodeNumericTypesBaseline", test_encodeDecodeNumericTypesBaseline),
14821543
("test_nestedContainerCodingPaths", test_nestedContainerCodingPaths),
14831544
("test_superEncoderCodingPaths", test_superEncoderCodingPaths),
14841545
("test_codingOfBool", test_codingOfBool),

0 commit comments

Comments
 (0)