diff --git a/Sources/FoundationEssentials/JSON/JSONDecoder.swift b/Sources/FoundationEssentials/JSON/JSONDecoder.swift index c7f5b7653..53e0032e0 100644 --- a/Sources/FoundationEssentials/JSON/JSONDecoder.swift +++ b/Sources/FoundationEssentials/JSON/JSONDecoder.swift @@ -610,7 +610,7 @@ extension JSONDecoderImpl: Decoder { if type == Decimal.self { return try self.unwrapDecimal(from: mapValue, for: codingPathNode, additionalKey) as! T } - if T.self is _JSONStringDictionaryDecodableMarker.Type { + if !options.keyDecodingStrategy.isDefault, T.self is _JSONStringDictionaryDecodableMarker.Type { return try self.unwrapDictionary(from: mapValue, as: type, for: codingPathNode, additionalKey) } @@ -1857,5 +1857,14 @@ extension EncodingError { } } +fileprivate extension JSONDecoder.KeyDecodingStrategy { + var isDefault: Bool { + switch self { + case .useDefaultKeys: true + default: false + } + } +} + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) extension JSONDecoder : @unchecked Sendable {} diff --git a/Sources/FoundationEssentials/JSON/JSONEncoder.swift b/Sources/FoundationEssentials/JSON/JSONEncoder.swift index 84159bbd1..8ec487ab3 100644 --- a/Sources/FoundationEssentials/JSON/JSONEncoder.swift +++ b/Sources/FoundationEssentials/JSON/JSONEncoder.swift @@ -1214,9 +1214,9 @@ private extension __JSONEncoder { return self.wrap(url.absoluteString) } else if let decimal = value as? Decimal { return .number(decimal.description) - } else if let encodable = value as? _JSONStringDictionaryEncodableMarker { + } else if !options.keyEncodingStrategy.isDefault, let encodable = value as? _JSONStringDictionaryEncodableMarker { return try self.wrap(encodable as! [String:Encodable], for: additionalKey) - } else if let array = value as? _JSONDirectArrayEncodable { + } else if let array = _asDirectArrayEncodable(value, for: additionalKey) { if options.outputFormatting.contains(.prettyPrinted) { let (bytes, lengths) = try array.individualElementRepresentation(encoder: self, additionalKey) return .directArray(bytes, lengths: lengths) @@ -1246,6 +1246,42 @@ private extension __JSONEncoder { return encoder.takeValue() } + func _asDirectArrayEncodable(_ value: T, for additionalKey: (some CodingKey)? = _CodingKey?.none) -> _JSONDirectArrayEncodable? { + return if let array = _specializingCast(array, to: [Int8].self) { + array + } else if let array = _specializingCast(array, to: [Int16].self) { + array + } else if let array = _specializingCast(array, to: [Int32].self) { + array + } else if let array = _specializingCast(array, to: [Int64].self) { + array + } else if let array = _specializingCast(array, to: [Int128].self) { + array + } else if let array = _specializingCast(array, to: [Int].self) { + array + } else if let array = _specializingCast(array, to: [UInt8].self) { + array + } else if let array = _specializingCast(array, to: [UInt16].self) { + array + } else if let array = _specializingCast(array, to: [UInt32].self) { + array + } else if let array = _specializingCast(array, to: [UInt64].self) { + array + } else if let array = _specializingCast(array, to: [UInt128].self) { + array + } else if let array = _specializingCast(array, to: [UInt].self) { + array + } else if let array = _specializingCast(array, to: [String].self) { + array + } else if let array = _specializingCast(array, to: [Float].self) { + array + } else if let array = _specializingCast(array, to: [Double].self) { + array + } else { + nil + } + } + @inline(__always) func getEncoder(for additionalKey: CodingKey?) -> __JSONEncoder { if let additionalKey { @@ -1466,3 +1502,14 @@ extension Array : _JSONDirectArrayEncodable where Element: _JSONSimpleValueArray return (writer.bytes, lengths: byteLengths) } } + +fileprivate extension JSONEncoder.KeyEncodingStrategy { + var isDefault: Bool { + switch self { + case .useDefaultKeys: + return true + case .custom, .convertToSnakeCase: + return false + } + } +}