@@ -129,13 +129,11 @@ open class JSONEncoder {
129
129
/// - throws: An error if any value throws an error during encoding.
130
130
open func encode< T : Encodable > ( _ value: T ) throws -> Data {
131
131
let encoder = _JSONEncoder ( options: self . options)
132
- try value. encode ( to: encoder)
133
132
134
- guard encoder . storage . count > 0 else {
133
+ guard let topLevel = try encoder . box_ ( value ) else {
135
134
throw EncodingError . invalidValue ( value, EncodingError . Context ( codingPath: [ ] , debugDescription: " Top-level \( T . self) did not encode any values. " ) )
136
135
}
137
136
138
- let topLevel = encoder. storage. popContainer ( )
139
137
if topLevel is NSNull {
140
138
throw EncodingError . invalidValue ( value, EncodingError . Context ( codingPath: [ ] , debugDescription: " Top-level \( T . self) encoded as null JSON fragment. " ) )
141
139
} else if topLevel is NSNumber {
@@ -468,77 +466,77 @@ extension _JSONEncoder : SingleValueEncodingContainer {
468
466
469
467
public func encode( _ value: Bool ) throws {
470
468
assertCanEncodeNewValue ( )
471
- self . storage. push ( container: box ( value) )
469
+ self . storage. push ( container: self . box ( value) )
472
470
}
473
471
474
472
public func encode( _ value: Int ) throws {
475
473
assertCanEncodeNewValue ( )
476
- self . storage. push ( container: box ( value) )
474
+ self . storage. push ( container: self . box ( value) )
477
475
}
478
476
479
477
public func encode( _ value: Int8 ) throws {
480
478
assertCanEncodeNewValue ( )
481
- self . storage. push ( container: box ( value) )
479
+ self . storage. push ( container: self . box ( value) )
482
480
}
483
481
484
482
public func encode( _ value: Int16 ) throws {
485
483
assertCanEncodeNewValue ( )
486
- self . storage. push ( container: box ( value) )
484
+ self . storage. push ( container: self . box ( value) )
487
485
}
488
486
489
487
public func encode( _ value: Int32 ) throws {
490
488
assertCanEncodeNewValue ( )
491
- self . storage. push ( container: box ( value) )
489
+ self . storage. push ( container: self . box ( value) )
492
490
}
493
491
494
492
public func encode( _ value: Int64 ) throws {
495
493
assertCanEncodeNewValue ( )
496
- self . storage. push ( container: box ( value) )
494
+ self . storage. push ( container: self . box ( value) )
497
495
}
498
496
499
497
public func encode( _ value: UInt ) throws {
500
498
assertCanEncodeNewValue ( )
501
- self . storage. push ( container: box ( value) )
499
+ self . storage. push ( container: self . box ( value) )
502
500
}
503
501
504
502
public func encode( _ value: UInt8 ) throws {
505
503
assertCanEncodeNewValue ( )
506
- self . storage. push ( container: box ( value) )
504
+ self . storage. push ( container: self . box ( value) )
507
505
}
508
506
509
507
public func encode( _ value: UInt16 ) throws {
510
508
assertCanEncodeNewValue ( )
511
- self . storage. push ( container: box ( value) )
509
+ self . storage. push ( container: self . box ( value) )
512
510
}
513
511
514
512
public func encode( _ value: UInt32 ) throws {
515
513
assertCanEncodeNewValue ( )
516
- self . storage. push ( container: box ( value) )
514
+ self . storage. push ( container: self . box ( value) )
517
515
}
518
516
519
517
public func encode( _ value: UInt64 ) throws {
520
518
assertCanEncodeNewValue ( )
521
- self . storage. push ( container: box ( value) )
519
+ self . storage. push ( container: self . box ( value) )
522
520
}
523
521
524
522
public func encode( _ value: String ) throws {
525
523
assertCanEncodeNewValue ( )
526
- self . storage. push ( container: box ( value) )
524
+ self . storage. push ( container: self . box ( value) )
527
525
}
528
526
529
527
public func encode( _ value: Float ) throws {
530
528
assertCanEncodeNewValue ( )
531
- try self . storage. push ( container: box ( value) )
529
+ try self . storage. push ( container: self . box ( value) )
532
530
}
533
531
534
532
public func encode( _ value: Double ) throws {
535
533
assertCanEncodeNewValue ( )
536
- try self . storage. push ( container: box ( value) )
534
+ try self . storage. push ( container: self . box ( value) )
537
535
}
538
536
539
537
public func encode< T : Encodable > ( _ value: T ) throws {
540
538
assertCanEncodeNewValue ( )
541
- try self . storage. push ( container: box ( value) )
539
+ try self . storage. push ( container: self . box ( value) )
542
540
}
543
541
}
544
542
@@ -661,28 +659,32 @@ extension _JSONEncoder {
661
659
}
662
660
663
661
fileprivate func box< T : Encodable > ( _ value: T ) throws -> NSObject {
664
- if T . self == Date . self {
662
+ return try self . box_ ( value) ?? NSDictionary ( )
663
+ }
664
+
665
+ // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want.
666
+ fileprivate func box_< T : Encodable > ( _ value: T ) throws -> NSObject ? {
667
+ if T . self == Date . self || T . self == NSDate . self {
665
668
// Respect Date encoding strategy
666
669
return try self . box ( ( value as! Date ) )
667
- } else if T . self == Data . self {
670
+ } else if T . self == Data . self || T . self == NSData . self {
668
671
// Respect Data encoding strategy
669
672
return try self . box ( ( value as! Data ) )
670
- } else if T . self == URL . self {
673
+ } else if T . self == URL . self || T . self == NSURL . self {
671
674
// Encode URLs as single strings.
672
675
return self . box ( ( value as! URL ) . absoluteString)
673
- } else if T . self == Decimal . self {
676
+ } else if T . self == Decimal . self || T . self == NSDecimalNumber . self {
674
677
// JSONSerialization can natively handle NSDecimalNumber.
675
- return ( value as! Decimal ) as NSDecimalNumber
678
+ return ( value as! NSDecimalNumber )
676
679
}
677
680
678
681
// The value should request a container from the _JSONEncoder.
679
- let topContainer = self . storage. containers . last
682
+ let depth = self . storage. count
680
683
try value. encode ( to: self )
681
684
682
685
// The top container should be a new container.
683
- guard self . storage. containers. last! !== topContainer else {
684
- // If the value didn't request a container at all, encode the default container instead.
685
- return NSDictionary ( )
686
+ guard self . storage. count > depth else {
687
+ return nil
686
688
}
687
689
688
690
return self . storage. popContainer ( )
@@ -865,7 +867,11 @@ open class JSONDecoder {
865
867
}
866
868
867
869
let decoder = _JSONDecoder ( referencing: topLevel, options: self . options)
868
- return try T ( from: decoder)
870
+ guard let value = try decoder. unbox ( topLevel, as: T . self) else {
871
+ throw DecodingError . valueNotFound ( T . self, DecodingError . Context ( codingPath: [ ] , debugDescription: " The given data did not contain a top-level value. " ) )
872
+ }
873
+
874
+ return value
869
875
}
870
876
}
871
877
@@ -2088,13 +2094,13 @@ extension _JSONDecoder {
2088
2094
2089
2095
fileprivate func unbox< T : Decodable > ( _ value: Any , as type: T . Type ) throws -> T ? {
2090
2096
let decoded : T
2091
- if T . self == Date . self {
2097
+ if T . self == Date . self || T . self == NSDate . self {
2092
2098
guard let date = try self . unbox ( value, as: Date . self) else { return nil }
2093
2099
decoded = date as! T
2094
- } else if T . self == Data . self {
2100
+ } else if T . self == Data . self || T . self == NSData . self {
2095
2101
guard let data = try self . unbox ( value, as: Data . self) else { return nil }
2096
2102
decoded = data as! T
2097
- } else if T . self == URL . self {
2103
+ } else if T . self == URL . self || T . self == NSURL . self {
2098
2104
guard let urlString = try self . unbox ( value, as: String . self) else {
2099
2105
return nil
2100
2106
}
@@ -2105,7 +2111,7 @@ extension _JSONDecoder {
2105
2111
}
2106
2112
2107
2113
decoded = ( url as! T )
2108
- } else if T . self == Decimal . self {
2114
+ } else if T . self == Decimal . self || T . self == NSDecimalNumber . self {
2109
2115
guard let decimal = try self . unbox ( value, as: Decimal . self) else { return nil }
2110
2116
decoded = decimal as! T
2111
2117
} else {
0 commit comments