diff --git a/Sources/PotentASN1/Dates.swift b/Sources/PotentASN1/Dates.swift index 7a9ef4fc3..0f5205edc 100644 --- a/Sources/PotentASN1/Dates.swift +++ b/Sources/PotentASN1/Dates.swift @@ -62,7 +62,9 @@ public struct SuffixedDateFormatter { public func date(from string: String) -> ZonedDate? { let parsedDate: Date? - let zoneStartIndex = string.firstIndex { char in char == "-" || char == "+" || char == "Z" } ?? string.endIndex + let zoneStartIndex = string.firstIndex { (char: Character) in + char == "-" || char == "+" || char == "Z" + } ?? string.endIndex let stringWithoutZone = String(string[string.startIndex ..< zoneStartIndex]) let hasSeconds = checkHasSeconds(stringWithoutZone) let hasZone = string != stringWithoutZone diff --git a/Sources/PotentCBOR/CBORDecoder.swift b/Sources/PotentCBOR/CBORDecoder.swift index 8751579e3..f2219eac2 100644 --- a/Sources/PotentCBOR/CBORDecoder.swift +++ b/Sources/PotentCBOR/CBORDecoder.swift @@ -173,6 +173,24 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser public static func unbox(_ value: CBOR, type: T.Type, decoder: IVD) throws -> T? where T: BinaryFloatingPoint, T: LosslessStringConvertible { + + func decode(fromDecimalFraction items: [CBOR]) throws -> T { + guard + let exp = try? unbox(items[0], type: Int.self, decoder: decoder), + let man = try? unbox(items[1], type: BigInt.self, decoder: decoder) + else { + throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) + } + guard let sig = Decimal(string: man.magnitude.description) else { + throw overflow(type, value: value, at: decoder.codingPath) + } + let dec = Decimal(sign: man.sign == .plus ? .plus : .minus, exponent: exp, significand: sig) + guard let result = T(dec.description) else { + throw overflow(type, value: value, at: decoder.codingPath) + } + return result + } + switch value { case .simple(let int): return try coerce(int, at: decoder.codingPath) @@ -198,26 +216,24 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser default: throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) } + } - func decode(fromDecimalFraction items: [CBOR]) throws -> T { + public static func unbox(_ value: CBOR, type: Decimal.Type, decoder: IVD) throws -> Decimal? { + + func decode(fromDecimalFraction items: [CBOR]) throws -> Decimal { guard let exp = try? unbox(items[0], type: Int.self, decoder: decoder), let man = try? unbox(items[1], type: BigInt.self, decoder: decoder) else { throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) } + // CHECK: Decimal(exactly:) is a fatal error for all inputs? guard let sig = Decimal(string: man.magnitude.description) else { - throw overflow(type, value: value, at: decoder.codingPath) - } - let dec = Decimal(sign: man.sign == .plus ? .plus : .minus, exponent: exp, significand: sig) - guard let result = T(dec.description) else { - throw overflow(type, value: value, at: decoder.codingPath) + throw overflow(Decimal.self, value: value, at: decoder.codingPath) } - return result + return Decimal(sign: man.sign == .plus ? .plus : .minus, exponent: exp, significand: sig) } - } - public static func unbox(_ value: CBOR, type: Decimal.Type, decoder: IVD) throws -> Decimal? { switch value { case .simple(let int): return Decimal(int) @@ -249,20 +265,6 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser default: throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) } - - func decode(fromDecimalFraction items: [CBOR]) throws -> Decimal { - guard - let exp = try? unbox(items[0], type: Int.self, decoder: decoder), - let man = try? unbox(items[1], type: BigInt.self, decoder: decoder) - else { - throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) - } - // CHECK: Decimal(exactly:) is a fatal error for all inputs? - guard let sig = Decimal(string: man.magnitude.description) else { - throw overflow(Decimal.self, value: value, at: decoder.codingPath) - } - return Decimal(sign: man.sign == .plus ? .plus : .minus, exponent: exp, significand: sig) - } } public static func unbox(_ value: CBOR, as type: Int.Type, decoder: IVD) throws -> Int? { @@ -331,16 +333,6 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser } public static func unbox(_ value: CBOR, as type: UUID.Type, decoder: IVD) throws -> UUID? { - switch value { - case .utf8String(let string), .tagged(.uuid, .utf8String(let string)): - return try decode(from: string) - case .byteString(let data), .tagged(.uuid, .byteString(let data)): - return try decode(from: data) - case .tagged(_, let tagged): return try unbox(tagged, as: type, decoder: decoder) - case .null: return nil - default: - throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) - } func decode(from string: String) throws -> UUID { guard let result = UUID(uuidString: string) else { @@ -360,6 +352,17 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser } return UUID(uuid: uuid) } + + switch value { + case .utf8String(let string), .tagged(.uuid, .utf8String(let string)): + return try decode(from: string) + case .byteString(let data), .tagged(.uuid, .byteString(let data)): + return try decode(from: data) + case .tagged(_, let tagged): return try unbox(tagged, as: type, decoder: decoder) + case .null: return nil + default: + throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) + } } public static func unbox(_ value: CBOR, as type: URL.Type, decoder: IVD) throws -> URL? { @@ -378,6 +381,25 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser public static func unbox(_ value: CBOR, as type: Date.Type, decoder: IVD) throws -> Date? { + func decode(from string: String) throws -> Date { + guard let date = ZonedDate(iso8601Encoded: string) else { + throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, + debugDescription: "Expected date string to be ISO8601-formatted.")) + } + return date.utcDate + } + + func decode(fromUntaggedNumericDate value: TimeInterval, unitsPerSeconds: Double) -> Date { + switch decoder.options.untaggedDateDecodingStrategy { + case .unitsSince1970: + return Date(timeIntervalSince1970: value / unitsPerSeconds) + case .millisecondsSince1970: + return Date(timeIntervalSince1970: value / 1000.0) + case .secondsSince1970: + return Date(timeIntervalSince1970: value) + } + } + switch value { case .utf8String(let string), .tagged(.iso8601DateTime, .utf8String(let string)): return try decode(from: string) @@ -397,25 +419,6 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser default: throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) } - - func decode(from string: String) throws -> Date { - guard let date = ZonedDate(iso8601Encoded: string) else { - throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, - debugDescription: "Expected date string to be ISO8601-formatted.")) - } - return date.utcDate - } - - func decode(fromUntaggedNumericDate value: TimeInterval, unitsPerSeconds: Double) -> Date { - switch decoder.options.untaggedDateDecodingStrategy { - case .unitsSince1970: - return Date(timeIntervalSince1970: value / unitsPerSeconds) - case .millisecondsSince1970: - return Date(timeIntervalSince1970: value / 1000.0) - case .secondsSince1970: - return Date(timeIntervalSince1970: value) - } - } } public static func unbox(_ value: CBOR, as type: Data.Type, decoder: IVD) throws -> Data? { @@ -467,6 +470,15 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser } public static func unbox(_ value: CBOR, as type: AnyValue.Type, decoder: IVD) throws -> AnyValue { + + func dictionary(from value: CBOR.Map) throws -> AnyValue { + return .dictionary(.init(uniqueKeysWithValues: try value.map { key, value in + let key = try unbox(key, as: AnyValue.self, decoder: decoder) + let value = try unbox(value, as: AnyValue.self, decoder: decoder) + return (key, value) + })) + } + switch value { case .null, .undefined: return .nil @@ -521,14 +533,6 @@ public struct CBORDecoderTransform: InternalDecoderTransform, InternalValueDeser case .tagged(_, let untagged): return try unbox(untagged, as: AnyValue.self, decoder: decoder) } - - func dictionary(from value: CBOR.Map) throws -> AnyValue { - return .dictionary(.init(uniqueKeysWithValues: try value.map { key, value in - let key = try unbox(key, as: AnyValue.self, decoder: decoder) - let value = try unbox(value, as: AnyValue.self, decoder: decoder) - return (key, value) - })) - } } public static func valueToUnkeyedValues(_ value: CBOR, decoder: IVD) throws -> UnkeyedValues? { diff --git a/Sources/PotentCBOR/CBOREncoder.swift b/Sources/PotentCBOR/CBOREncoder.swift index 52b655550..d3cbc6ea2 100644 --- a/Sources/PotentCBOR/CBOREncoder.swift +++ b/Sources/PotentCBOR/CBOREncoder.swift @@ -183,6 +183,15 @@ public struct CBOREncoderTransform: InternalEncoderTransform, InternalValueSeria } public static func box(_ value: AnyValue, encoder: IVE) throws -> CBOR { + + func encode(_ value: AnyValue.AnyDictionary) throws -> CBOR { + return .map(.init(uniqueKeysWithValues: try value.map { key, value in + let key = try box(key, encoder: encoder) + let value = try box(value, encoder: encoder) + return (key, value) + })) + } + switch value { case .nil: return .null @@ -231,14 +240,6 @@ public struct CBOREncoderTransform: InternalEncoderTransform, InternalValueSeria case .dictionary(let value): return try encode(value) } - - func encode(_ value: AnyValue.AnyDictionary) throws -> CBOR { - return .map(.init(uniqueKeysWithValues: try value.map { key, value in - let key = try box(key, encoder: encoder) - let value = try box(value, encoder: encoder) - return (key, value) - })) - } } public static func unkeyedValuesToValue(_ values: UnkeyedValues, encoder: IVE) -> CBOR { diff --git a/Sources/PotentCodables/AnyValue/AnyValue.swift b/Sources/PotentCodables/AnyValue/AnyValue.swift index ad5c41cd3..798f077f0 100644 --- a/Sources/PotentCodables/AnyValue/AnyValue.swift +++ b/Sources/PotentCodables/AnyValue/AnyValue.swift @@ -376,6 +376,26 @@ extension AnyValue { } public var unwrapped: Any? { + + func unwrap(dictionary: AnyDictionary) -> Any { + return Dictionary(uniqueKeysWithValues: dictionary.compactMap { + guard let value = $1.unwrapped else { + return nil + } + if let key = $0.stringValue { + return (AnyHashable(key), value) + } + else if let key = $0.integerValue(Int.self) { + return (AnyHashable(key), value) + } + else { + // It is an unsupported key type, but we are returning + // nil(s) rather than throwing errors + return nil + } + }) as [AnyHashable: Any] + } + switch self { case .nil: return nil case .bool(let value): return value @@ -401,25 +421,6 @@ extension AnyValue { case .array(let value): return Array(value.map(\.unwrapped)) case .dictionary(let value): return unwrap(dictionary: value) } - - func unwrap(dictionary: AnyDictionary) -> Any { - return Dictionary(uniqueKeysWithValues: dictionary.compactMap { - guard let value = $1.unwrapped else { - return nil - } - if let key = $0.stringValue { - return (AnyHashable(key), value) - } - else if let key = $0.integerValue(Int.self) { - return (AnyHashable(key), value) - } - else { - // It is an unsupported key type, but we are returning - // nil(s) rather than throwing errors - return nil - } - }) as [AnyHashable: Any] - } } } diff --git a/Sources/PotentCodables/ZonedDate.swift b/Sources/PotentCodables/ZonedDate.swift index bf99f1292..4ee6c41e2 100644 --- a/Sources/PotentCodables/ZonedDate.swift +++ b/Sources/PotentCodables/ZonedDate.swift @@ -120,7 +120,9 @@ private struct ISO8601FlexibleDateFormatter { let timeZone: TimeZone if let timeStartIndex = string.firstIndex(of: "T") { let time = string[timeStartIndex...] - let zoneStartIndex = time.firstIndex { char in char == "-" || char == "+" || char == "Z" } ?? time.endIndex + let zoneStartIndex = time.firstIndex { (char: Character) in + char == "-" || char == "+" || char == "Z" + } ?? time.endIndex let timeWithoutZone = time[time.startIndex ..< zoneStartIndex] hasSeconds = timeWithoutZone.contains(".") hasZone = zoneStartIndex != time.endIndex diff --git a/Sources/PotentJSON/JSONDecoder.swift b/Sources/PotentJSON/JSONDecoder.swift index 0e2122ade..6bc3afb5c 100644 --- a/Sources/PotentJSON/JSONDecoder.swift +++ b/Sources/PotentJSON/JSONDecoder.swift @@ -394,27 +394,6 @@ public struct JSONDecoderTransform: InternalDecoderTransform, InternalValueDeser } public static func unbox(_ value: JSON, as type: Date.Type, decoder: IVD) throws -> Date? { - guard !value.isNull else { return nil } - - switch decoder.options.dateDecodingStrategy { - case .deferredToDate: - return try decoder.subDecode(with: value) { try Date(from: $0) } - - case .secondsSince1970: - return try unbox(value, as: Double.self, decoder: decoder).map { Date(timeIntervalSince1970: $0) } - - case .millisecondsSince1970: - return try unbox(value, as: Double.self, decoder: decoder).map { Date(timeIntervalSince1970: $0 / 1000.0) } - - case .iso8601: - return try decodeISO8601(from: value) - - case .formatted(let formatter): - return try decodeFormatted(from: value, formatter: formatter) - - case .custom(let closure): - return try decoder.subDecode(with: value) { try closure($0) } - } func decodeISO8601(from value: JSON) throws -> Date? { guard let string = try unbox(value, as: String.self, decoder: decoder) else { @@ -441,21 +420,31 @@ public struct JSONDecoderTransform: InternalDecoderTransform, InternalValueDeser } return date } - } - public static func unbox(_ value: JSON, as type: Data.Type, decoder: IVD) throws -> Data? { guard !value.isNull else { return nil } - switch decoder.options.dataDecodingStrategy { - case .deferredToData: - return try decoder.subDecode(with: value) { try Data(from: $0) } + switch decoder.options.dateDecodingStrategy { + case .deferredToDate: + return try decoder.subDecode(with: value) { try Date(from: $0) } - case .base64: - return try decodeBase64(from: value) + case .secondsSince1970: + return try unbox(value, as: Double.self, decoder: decoder).map { Date(timeIntervalSince1970: $0) } + + case .millisecondsSince1970: + return try unbox(value, as: Double.self, decoder: decoder).map { Date(timeIntervalSince1970: $0 / 1000.0) } + + case .iso8601: + return try decodeISO8601(from: value) + + case .formatted(let formatter): + return try decodeFormatted(from: value, formatter: formatter) case .custom(let closure): return try decoder.subDecode(with: value) { try closure($0) } } + } + + public static func unbox(_ value: JSON, as type: Data.Type, decoder: IVD) throws -> Data? { func decodeBase64(from value: JSON) throws -> Data { guard case .string(let string) = value else { @@ -471,25 +460,22 @@ public struct JSONDecoderTransform: InternalDecoderTransform, InternalValueDeser return data } + + guard !value.isNull else { return nil } + + switch decoder.options.dataDecodingStrategy { + case .deferredToData: + return try decoder.subDecode(with: value) { try Data(from: $0) } + + case .base64: + return try decodeBase64(from: value) + + case .custom(let closure): + return try decoder.subDecode(with: value) { try closure($0) } + } } public static func unbox(_ value: JSON, as type: AnyValue.Type, decoder: IVD) throws -> AnyValue { - switch value { - case .null: - return .nil - case .bool(let value): - return .bool(value) - case .string(let value): - return .string(value) - case .number(let value): - return decode(from: value) - case .array(let value): - return .array(try value.map { try unbox($0, as: AnyValue.self, decoder: decoder) }) - case .object(let value): - return .dictionary(AnyValue.AnyDictionary(uniqueKeysWithValues: try value.map { key, value in - (.string(key), try unbox(value, as: AnyValue.self, decoder: decoder)) - })) - } func decode(from value: JSON.Number) -> AnyValue { switch value.numberValue { @@ -510,6 +496,23 @@ public struct JSONDecoderTransform: InternalDecoderTransform, InternalValueDeser fatalError("numberValue returned unsupported value") } } + + switch value { + case .null: + return .nil + case .bool(let value): + return .bool(value) + case .string(let value): + return .string(value) + case .number(let value): + return decode(from: value) + case .array(let value): + return .array(try value.map { try unbox($0, as: AnyValue.self, decoder: decoder) }) + case .object(let value): + return .dictionary(AnyValue.AnyDictionary(uniqueKeysWithValues: try value.map { key, value in + (.string(key), try unbox(value, as: AnyValue.self, decoder: decoder)) + })) + } } public static func valueToUnkeyedValues(_ value: JSON, decoder: IVD) throws -> UnkeyedValues? { diff --git a/Sources/PotentJSON/JSONEncoder.swift b/Sources/PotentJSON/JSONEncoder.swift index 89f282655..cae3c03ba 100644 --- a/Sources/PotentJSON/JSONEncoder.swift +++ b/Sources/PotentJSON/JSONEncoder.swift @@ -346,6 +346,21 @@ public struct JSONEncoderTransform: InternalEncoderTransform, InternalValueSeria } public static func box(_ value: AnyValue, encoder: IVE) throws -> JSON { + + func encodeObject(from value: AnyValue.AnyDictionary) throws -> JSON.Object { + return JSON.Object(uniqueKeysWithValues: try value.map { key, value in + let boxedValue = try box(value, encoder: encoder) + if let stringKey = key.stringValue { + return (stringKey, boxedValue) + } + else if let intKey = key.integerValue(Int.self) { + return (String(intKey), boxedValue) + } + throw EncodingError.invalidValue(value, .init(codingPath: encoder.codingPath, + debugDescription: "Dictionary contains non-string values")) + }) + } + switch value { case .nil: return .null @@ -394,20 +409,6 @@ public struct JSONEncoderTransform: InternalEncoderTransform, InternalValueSeria case .dictionary(let value): return .object(try encodeObject(from: value)) } - - func encodeObject(from value: AnyValue.AnyDictionary) throws -> JSON.Object { - return JSON.Object(uniqueKeysWithValues: try value.map { key, value in - let boxedValue = try box(value, encoder: encoder) - if let stringKey = key.stringValue { - return (stringKey, boxedValue) - } - else if let intKey = key.integerValue(Int.self) { - return (String(intKey), boxedValue) - } - throw EncodingError.invalidValue(value, .init(codingPath: encoder.codingPath, - debugDescription: "Dictionary contains non-string values")) - }) - } } public static func unkeyedValuesToValue(_ values: UnkeyedValues, encoder: IVE) -> JSON { diff --git a/Sources/PotentYAML/YAMLDecoder.swift b/Sources/PotentYAML/YAMLDecoder.swift index 6b33fc514..44f4f8b1d 100644 --- a/Sources/PotentYAML/YAMLDecoder.swift +++ b/Sources/PotentYAML/YAMLDecoder.swift @@ -337,13 +337,6 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser } public static func unbox(_ value: YAML, as type: Decimal.Type, decoder: IVD) throws -> Decimal? { - switch value { - case .integer(let number, _): return try decodeInteger(number) - case .float(let number, _): return try decodeFloat(number) - case .null: return nil - case let yaml: - throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: yaml) - } func decodeInteger(_ number: YAML.Number) throws -> Decimal { guard let decimal = Decimal(string: number.value) else { @@ -373,6 +366,14 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser } return decimal } + + switch value { + case .integer(let number, _): return try decodeInteger(number) + case .float(let number, _): return try decodeFloat(number) + case .null: return nil + case let yaml: + throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: yaml) + } } public static func unbox(_ value: YAML, as type: String.Type, decoder: IVD) throws -> String? { @@ -412,27 +413,6 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser } public static func unbox(_ value: YAML, as type: Date.Type, decoder: IVD) throws -> Date? { - guard !value.isNull else { return nil } - - switch decoder.options.dateDecodingStrategy { - case .deferredToDate: - return try decoder.subDecode(with: value) { try Date(from: $0) } - - case .secondsSince1970: - return try unbox(value, as: Double.self, decoder: decoder).map { Date(timeIntervalSince1970: $0) } - - case .millisecondsSince1970: - return try unbox(value, as: Double.self, decoder: decoder).map { Date(timeIntervalSince1970: $0 / 1000.0) } - - case .iso8601: - return try decodeISO8601(from: value) - - case .formatted(let formatter): - return try decodeFormatted(from: value, formatter: formatter) - - case .custom(let closure): - return try decoder.subDecode(with: value) { try closure($0) } - } func decodeISO8601(from value: YAML) throws -> Date? { guard let string = try unbox(value, as: String.self, decoder: decoder) else { @@ -459,21 +439,31 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser } return date } - } - public static func unbox(_ value: YAML, as type: Data.Type, decoder: IVD) throws -> Data? { guard !value.isNull else { return nil } - switch decoder.options.dataDecodingStrategy { - case .deferredToData: - return try decoder.subDecode(with: value) { try Data(from: $0) } + switch decoder.options.dateDecodingStrategy { + case .deferredToDate: + return try decoder.subDecode(with: value) { try Date(from: $0) } - case .base64: - return try decodeBase64(from: value) + case .secondsSince1970: + return try unbox(value, as: Double.self, decoder: decoder).map { Date(timeIntervalSince1970: $0) } + + case .millisecondsSince1970: + return try unbox(value, as: Double.self, decoder: decoder).map { Date(timeIntervalSince1970: $0 / 1000.0) } + + case .iso8601: + return try decodeISO8601(from: value) + + case .formatted(let formatter): + return try decodeFormatted(from: value, formatter: formatter) case .custom(let closure): return try decoder.subDecode(with: value) { try closure($0) } } + } + + public static func unbox(_ value: YAML, as type: Data.Type, decoder: IVD) throws -> Data? { func decodeBase64(from value: YAML) throws -> Data { guard case .string(let string, _, _, _) = value else { @@ -489,29 +479,22 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser return data } + + guard !value.isNull else { return nil } + + switch decoder.options.dataDecodingStrategy { + case .deferredToData: + return try decoder.subDecode(with: value) { try Data(from: $0) } + + case .base64: + return try decodeBase64(from: value) + + case .custom(let closure): + return try decoder.subDecode(with: value) { try closure($0) } + } } public static func unbox(_ value: YAML, as type: AnyValue.Type, decoder: IVD) throws -> AnyValue { - switch value { - case .null: - return .nil - case .bool(let value, _): - return .bool(value) - case .string(let value, _, _, _): - return .string(value) - case .integer(let value, anchor: _), .float(let value, anchor: _): - return decode(from: value) - case .sequence(let value, _, _, _): - return .array(try value.map { try unbox($0, as: AnyValue.self, decoder: decoder) }) - case .mapping(let value, _, _, _): - return .dictionary(AnyValue.AnyDictionary(uniqueKeysWithValues: try value.map { entry in - (try unbox(entry.key, as: AnyValue.self, decoder: decoder), - try unbox(entry.value, as: AnyValue.self, decoder: decoder)) - })) - default: - break - } - throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) func decode(from value: YAML.Number) -> AnyValue { switch value.numberValue { @@ -532,6 +515,27 @@ public struct YAMLDecoderTransform: InternalDecoderTransform, InternalValueDeser fatalError("numberValue returned unsupported value") } } + + switch value { + case .null: + return .nil + case .bool(let value, _): + return .bool(value) + case .string(let value, _, _, _): + return .string(value) + case .integer(let value, anchor: _), .float(let value, anchor: _): + return decode(from: value) + case .sequence(let value, _, _, _): + return .array(try value.map { try unbox($0, as: AnyValue.self, decoder: decoder) }) + case .mapping(let value, _, _, _): + return .dictionary(AnyValue.AnyDictionary(uniqueKeysWithValues: try value.map { entry in + (try unbox(entry.key, as: AnyValue.self, decoder: decoder), + try unbox(entry.value, as: AnyValue.self, decoder: decoder)) + })) + default: + break + } + throw DecodingError.typeMismatch(at: decoder.codingPath, expectation: type, reality: value) } public static func valueToUnkeyedValues(_ value: YAML, decoder: IVD) throws -> UnkeyedValues? { diff --git a/Tests/Assertions.swift b/Tests/Assertions.swift index 12eb03601..b6acd4601 100644 --- a/Tests/Assertions.swift +++ b/Tests/Assertions.swift @@ -15,7 +15,7 @@ import XCTest public func AssertDecodingTypeMismatch(_ error: Error, file: StaticString = #file, line: UInt = #line) { func check() -> Bool { - if case DecodingError.typeMismatch = error { + if case DecodingError.typeMismatch(_, _) = error { return true } else { diff --git a/Tests/JSONAnyValueTests.swift b/Tests/JSONAnyValueTests.swift index f62e81dd3..0be0c485b 100644 --- a/Tests/JSONAnyValueTests.swift +++ b/Tests/JSONAnyValueTests.swift @@ -17,7 +17,7 @@ import XCTest class JSONAnyValueTests: XCTestCase { - let prettyEncoder = { + let prettyEncoder: JSON.Encoder = { let enc = JSON.Encoder() enc.outputFormatting = .prettyPrinted return enc diff --git a/Tests/JSONEncoderTests.swift b/Tests/JSONEncoderTests.swift index 55e8eb352..0b84d4b75 100644 --- a/Tests/JSONEncoderTests.swift +++ b/Tests/JSONEncoderTests.swift @@ -1129,7 +1129,7 @@ class JSONEncoderTests: XCTestCase { XCTAssertNoThrow(try JSON.Encoder.default.encodeString(TestValue(dict: [1: 1]))) } - let prettyEncoder = { + let prettyEncoder: JSON.Encoder = { let enc = JSON.Encoder() enc.outputFormatting = .prettyPrinted return enc