Skip to content

Commit 026b459

Browse files
committed
New AnyCodable
fix pipeline remove objc type private class fixes old formatter fix iso8601 fix support swift 5.1 fix mr pr fixes add value encoding strategies Update Tests/AnyCodableTests/AnyCodableTests.swift
1 parent 3fac475 commit 026b459

14 files changed

+1106
-265
lines changed

Sources/OpenAPIKit/AnyCodable/AnyCodable.swift

Lines changed: 100 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -32,207 +32,81 @@ import Foundation
3232
and other collections that require `Encodable` or `Decodable` conformance
3333
by declaring their contained type to be `AnyCodable`.
3434
*/
35-
public struct AnyCodable {
36-
public let value: Any
37-
38-
public init<T>(_ value: T?) {
39-
self.value = value ?? ()
40-
}
35+
public enum AnyCodable: Equatable {
36+
37+
case string(String)
38+
case bool(Bool)
39+
case int(Int)
40+
case double(Double)
41+
case object([String: AnyCodable])
42+
case array([AnyCodable])
43+
case null
4144
}
4245

4346
extension AnyCodable: Encodable {
4447
public func encode(to encoder: Encoder) throws {
45-
var container = encoder.singleValueContainer()
46-
47-
switch value {
48-
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
49-
case let number as NSNumber:
50-
try encode(nsnumber: number, into: &container)
51-
#endif
52-
case is NSNull, is Void:
48+
switch self {
49+
case let .string(value): try value.encode(to: encoder)
50+
case let .bool(value): try value.encode(to: encoder)
51+
case let .int(value): try value.encode(to: encoder)
52+
case let .double(value): try value.encode(to: encoder)
53+
case let .object(value): try value.encode(to: encoder)
54+
case let .array(value): try value.encode(to: encoder)
55+
case .null:
56+
var container = encoder.singleValueContainer()
5357
try container.encodeNil()
54-
case let bool as Bool:
55-
try container.encode(bool)
56-
case let int as Int:
57-
try container.encode(int)
58-
case let int8 as Int8:
59-
try container.encode(int8)
60-
case let int16 as Int16:
61-
try container.encode(int16)
62-
case let int32 as Int32:
63-
try container.encode(int32)
64-
case let int64 as Int64:
65-
try container.encode(int64)
66-
case let uint as UInt:
67-
try container.encode(uint)
68-
case let uint8 as UInt8:
69-
try container.encode(uint8)
70-
case let uint16 as UInt16:
71-
try container.encode(uint16)
72-
case let uint32 as UInt32:
73-
try container.encode(uint32)
74-
case let uint64 as UInt64:
75-
try container.encode(uint64)
76-
case let float as Float:
77-
try container.encode(float)
78-
case let double as Double:
79-
try container.encode(double)
80-
case let string as String:
81-
try container.encode(string)
82-
case let date as Date:
83-
try container.encode(date)
84-
case let url as URL:
85-
try container.encode(url)
86-
case let array as [Any?]:
87-
try container.encode(array.map { AnyCodable($0) })
88-
case let dictionary as [String: Any?]:
89-
try container.encode(dictionary.mapValues { AnyCodable($0) })
90-
default:
91-
let context = EncodingError.Context(codingPath: container.codingPath, debugDescription: "AnyCodable value cannot be encoded")
92-
throw EncodingError.invalidValue(value, context)
93-
}
94-
}
95-
96-
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
97-
private func encode(nsnumber: NSNumber, into container: inout SingleValueEncodingContainer) throws {
98-
switch CFNumberGetType(nsnumber) {
99-
case .charType:
100-
try container.encode(nsnumber.boolValue)
101-
case .sInt8Type:
102-
try container.encode(nsnumber.int8Value)
103-
case .sInt16Type:
104-
try container.encode(nsnumber.int16Value)
105-
case .sInt32Type:
106-
try container.encode(nsnumber.int32Value)
107-
case .sInt64Type:
108-
try container.encode(nsnumber.int64Value)
109-
case .shortType:
110-
try container.encode(nsnumber.uint16Value)
111-
case .longType:
112-
try container.encode(nsnumber.uint32Value)
113-
case .longLongType:
114-
try container.encode(nsnumber.uint64Value)
115-
case .intType, .nsIntegerType, .cfIndexType:
116-
try container.encode(nsnumber.intValue)
117-
case .floatType, .float32Type:
118-
try container.encode(nsnumber.floatValue)
119-
case .doubleType, .float64Type, .cgFloatType:
120-
try container.encode(nsnumber.doubleValue)
121-
#if swift(>=5.0)
122-
@unknown default:
123-
fatalError()
124-
#endif
12558
}
12659
}
127-
#endif
12860
}
12961

13062
extension AnyCodable: Decodable {
13163
public init(from decoder: Decoder) throws {
13264
let container = try decoder.singleValueContainer()
13365

13466
if container.decodeNil() {
135-
self.init(NSNull())
67+
self = .null
13668
} else if let bool = try? container.decode(Bool.self) {
137-
self.init(bool)
69+
self = .bool(bool)
13870
} else if let int = try? container.decode(Int.self) {
139-
self.init(int)
140-
} else if let uint = try? container.decode(UInt.self) {
141-
self.init(uint)
71+
self = .int(int)
14272
} else if let double = try? container.decode(Double.self) {
143-
self.init(double)
73+
self = .double(double)
14474
} else if let string = try? container.decode(String.self) {
145-
self.init(string)
75+
self = .string(string)
14676
} else if let array = try? container.decode([AnyCodable].self) {
147-
self.init(array.map { $0.value })
77+
self = .array(array)
14878
} else if let dictionary = try? container.decode([String: AnyCodable].self) {
149-
self.init(dictionary.mapValues { $0.value })
79+
self = .object(dictionary)
15080
} else {
15181
throw DecodingError.dataCorruptedError(in: container, debugDescription: "AnyCodable value cannot be decoded")
15282
}
15383
}
15484
}
15585

156-
extension AnyCodable: Equatable {
157-
public static func == (lhs: AnyCodable, rhs: AnyCodable) -> Bool {
158-
switch (lhs.value, rhs.value) {
159-
case is (Void, Void):
160-
return true
161-
case let (lhs as Bool, rhs as Bool):
162-
return lhs == rhs
163-
case let (lhs as Int, rhs as Int):
164-
return lhs == rhs
165-
case let (lhs as Int8, rhs as Int8):
166-
return lhs == rhs
167-
case let (lhs as Int16, rhs as Int16):
168-
return lhs == rhs
169-
case let (lhs as Int32, rhs as Int32):
170-
return lhs == rhs
171-
case let (lhs as Int64, rhs as Int64):
172-
return lhs == rhs
173-
case let (lhs as UInt, rhs as UInt):
174-
return lhs == rhs
175-
case let (lhs as UInt8, rhs as UInt8):
176-
return lhs == rhs
177-
case let (lhs as UInt16, rhs as UInt16):
178-
return lhs == rhs
179-
case let (lhs as UInt32, rhs as UInt32):
180-
return lhs == rhs
181-
case let (lhs as UInt64, rhs as UInt64):
182-
return lhs == rhs
183-
case let (lhs as Float, rhs as Float):
184-
return lhs == rhs
185-
case let (lhs as Double, rhs as Double):
186-
return lhs == rhs
187-
case let (lhs as String, rhs as String):
188-
return lhs == rhs
189-
case let (lhs as [String: String], rhs as [String: String]):
190-
return lhs == rhs
191-
case let (lhs as [String: Int], rhs as [String: Int]):
192-
return lhs == rhs
193-
case let (lhs as [String: Double], rhs as [String: Double]):
194-
return lhs == rhs
195-
case let (lhs as [String: Bool], rhs as [String: Bool]):
196-
return lhs == rhs
197-
case let (lhs as [String: AnyCodable], rhs as [String: AnyCodable]):
198-
return lhs == rhs
199-
case let (lhs as [String], rhs as [String]):
200-
return lhs == rhs
201-
case let (lhs as [Int], rhs as [Int]):
202-
return lhs == rhs
203-
case let (lhs as [Double], rhs as [Double]):
204-
return lhs == rhs
205-
case let (lhs as [Bool], rhs as [Bool]):
206-
return lhs == rhs
207-
case let (lhs as [AnyCodable], rhs as [AnyCodable]):
208-
return lhs == rhs
209-
default:
210-
return false
211-
}
212-
}
213-
}
214-
21586
extension AnyCodable: CustomStringConvertible {
21687
public var description: String {
217-
switch value {
218-
case is Void:
219-
return String(describing: nil as Any?)
220-
case let value as CustomStringConvertible:
221-
return value.description
222-
default:
223-
return String(describing: value)
88+
switch self {
89+
case .string(let string):
90+
return "\"\(string.description)\""
91+
case .bool(let bool):
92+
return bool.description
93+
case .int(let int):
94+
return int.description
95+
case .double(let double):
96+
return double.description
97+
case .object(let dictionary):
98+
return "[\(dictionary.sorted(by: { $0.key < $1.key }).map { "\"\($0)\": \($1.description)" }.joined(separator: ", "))]"
99+
case .array(let array):
100+
return "[\(array.map { $0.description }.joined(separator: ", "))]"
101+
case .null:
102+
return "nil"
224103
}
225104
}
226105
}
227106

228107
extension AnyCodable: CustomDebugStringConvertible {
229108
public var debugDescription: String {
230-
switch value {
231-
case let value as CustomDebugStringConvertible:
232-
return "AnyCodable(\(value.debugDescription))"
233-
default:
234-
return "AnyCodable(\(description))"
235-
}
109+
"AnyCodable(\(description))"
236110
}
237111
}
238112

@@ -246,31 +120,81 @@ extension AnyCodable: ExpressibleByDictionaryLiteral {}
246120

247121
extension AnyCodable {
248122
public init(nilLiteral _: ()) {
249-
self.init(nil as Any?)
123+
self = .null
250124
}
251125

252126
public init(booleanLiteral value: Bool) {
253-
self.init(value)
127+
self = .bool(value)
254128
}
255129

256130
public init(integerLiteral value: Int) {
257-
self.init(value)
131+
self = .int(value)
258132
}
259133

260134
public init(floatLiteral value: Double) {
261-
self.init(value)
135+
self = .double(value)
262136
}
263137

264138
public init(stringLiteral value: String) {
265-
self.init(value)
139+
self = .string(value)
266140
}
267141

268-
public init(arrayLiteral elements: Any...) {
269-
self.init(elements)
142+
public init(arrayLiteral elements: AnyCodable...) {
143+
self = .array(elements)
270144
}
271145

272-
public init(dictionaryLiteral elements: (AnyHashable, Any)...) {
273-
self.init([AnyHashable: Any](elements, uniquingKeysWith: { first, _ in first }))
146+
public init(dictionaryLiteral elements: (String, AnyCodable)...) {
147+
self = .object([String: AnyCodable](elements, uniquingKeysWith: { first, _ in first }))
148+
}
149+
}
150+
151+
// MARK: Backward compatibility
152+
extension AnyCodable {
153+
public var value: Any {
154+
switch self {
155+
case .string(let string):
156+
return string
157+
case .bool(let bool):
158+
return bool
159+
case .int(let int):
160+
return int
161+
case .double(let double):
162+
return double
163+
case .object(let dictionary):
164+
return dictionary.mapValues { $0.value }
165+
case .array(let array):
166+
return array.map { $0.value }
167+
case .null:
168+
return Optional<Any>.none as Any
169+
}
170+
}
171+
172+
public init(_ value: Bool) {
173+
self = .bool(value)
174+
}
175+
176+
public init<T: BinaryInteger>(_ value: T) {
177+
self = .int(Int(value))
178+
}
179+
180+
public init<T: StringProtocol>(_ value: T) {
181+
self = .string(String(value))
182+
}
183+
184+
public init<T: BinaryFloatingPoint>(_ value: T) {
185+
self = .double(Double(value))
186+
}
187+
188+
public init(_ value: [AnyCodable]) {
189+
self = .array(value)
190+
}
191+
192+
public init(_ value: [String: AnyCodable]) {
193+
self = .object(value)
194+
}
195+
196+
public init(_ value: ()) {
197+
self = .null
274198
}
275199
}
276200

0 commit comments

Comments
 (0)