this repo has no description
1//
2// DecodingContainer+MultiValue.swift
3// URLQueryItemCoder
4//
5// Created by Kyle Hughes on 2/21/23.
6//
7
8import Foundation
9
10extension DecodingContainer {
11 internal final class MultiValue {
12 internal let configuration: DecodingStrategies
13
14 internal private(set) var children: [String: DecodingContainer<PrimitiveValue>]
15 internal private(set) var codingPath: [any CodingKey]
16 internal private(set) var currentIndex: Int
17
18 // MARK: Internal Initialization
19
20 internal init(codingPath: [any CodingKey], configuration: DecodingStrategies) {
21 self.codingPath = codingPath
22 self.configuration = configuration
23
24 children = [:]
25 currentIndex = 0
26 }
27
28 // MARK: Internal Instance Interface
29
30 internal func set(_ key: String, to child: DecodingContainer<PrimitiveValue>) {
31 precondition(children[key] == nil, "A child already exists for that key.")
32
33 children[key] = child
34 }
35
36 // MARK: Private Instance Interface
37
38 private var endIndex: Int {
39 children.count - 1
40 }
41
42 private func childContainer(for key: some CodingKey) throws -> DecodingContainer {
43 let encodedKey = configuration.keyStrategy.encode(key, at: codingPath)
44
45 guard let childContainer = children[encodedKey.stringValue] else {
46 throw DecodingError.keyNotFound(
47 key,
48 .noValueAssociatedWithKey(at: nextCodingPath(appending: key))
49 )
50 }
51
52 return childContainer
53 }
54
55 private func singleValueContainer(for key: some CodingKey) throws -> DecodingContainer.SingleValue {
56 switch try childContainer(for: key) {
57 case .multiValue:
58 throw DecodingError.dataCorrupted(
59 DecodingError.Context(
60 codingPath: codingPath,
61 debugDescription: "Cannot decode container as primitive value."
62 )
63 )
64 case let .singleValue(singleValueContainer):
65 return singleValueContainer
66 }
67 }
68
69 // MARK: Private Instance Interface
70
71 private func nextCodingPath(appending key: some CodingKey) -> [any CodingKey] {
72 var nextCodingPath = codingPath
73 nextCodingPath.append(key)
74
75 return nextCodingPath
76 }
77
78 private func nextDecodingKey() -> StringCodingKey {
79 defer {
80 currentIndex += 1
81 }
82
83 return StringCodingKey(intValue: currentIndex)
84 }
85 }
86}
87
88// MARK: - KeyedDecodingContainerProtocol Extension
89
90extension DecodingContainer.MultiValue: KeyedDecodingContainerProtocol {
91 // MARK: Internal Instance Interface
92
93 internal var allKeys: [StringCodingKey] {
94 children.keys.map(StringCodingKey.init(stringValue:))
95 }
96
97 internal func contains(_ key: StringCodingKey) -> Bool {
98 let encodedKey = configuration.keyStrategy.encode(key, at: codingPath)
99
100 return children[encodedKey.stringValue] != nil
101 }
102
103 internal func decode(_ type: Bool.Type, forKey key: StringCodingKey) throws -> Bool {
104 try singleValueContainer(for: key).decode(type)
105 }
106
107 internal func decode(_ type: String.Type, forKey key: StringCodingKey) throws -> String {
108 try singleValueContainer(for: key).decode(type)
109 }
110
111 internal func decode(_ type: Double.Type, forKey key: StringCodingKey) throws -> Double {
112 try singleValueContainer(for: key).decode(type)
113 }
114
115 internal func decode(_ type: Float.Type, forKey key: StringCodingKey) throws -> Float {
116 try singleValueContainer(for: key).decode(type)
117 }
118
119 internal func decode(_ type: Int.Type, forKey key: StringCodingKey) throws -> Int {
120 try singleValueContainer(for: key).decode(type)
121 }
122
123 internal func decode(_ type: Int8.Type, forKey key: StringCodingKey) throws -> Int8 {
124 try singleValueContainer(for: key).decode(type)
125 }
126
127 internal func decode(_ type: Int16.Type, forKey key: StringCodingKey) throws -> Int16 {
128 try singleValueContainer(for: key).decode(type)
129 }
130
131 internal func decode(_ type: Int32.Type, forKey key: StringCodingKey) throws -> Int32 {
132 try singleValueContainer(for: key).decode(type)
133 }
134
135 internal func decode(_ type: Int64.Type, forKey key: StringCodingKey) throws -> Int64 {
136 try singleValueContainer(for: key).decode(type)
137 }
138
139 internal func decode(_ type: UInt.Type, forKey key: StringCodingKey) throws -> UInt {
140 try singleValueContainer(for: key).decode(type)
141 }
142
143 internal func decode(_ type: UInt8.Type, forKey key: StringCodingKey) throws -> UInt8 {
144 try singleValueContainer(for: key).decode(type)
145 }
146
147 internal func decode(_ type: UInt16.Type, forKey key: StringCodingKey) throws -> UInt16 {
148 try singleValueContainer(for: key).decode(type)
149 }
150
151 internal func decode(_ type: UInt32.Type, forKey key: StringCodingKey) throws -> UInt32 {
152 try singleValueContainer(for: key).decode(type)
153 }
154
155 internal func decode(_ type: UInt64.Type, forKey key: StringCodingKey) throws -> UInt64 {
156 try singleValueContainer(for: key).decode(type)
157 }
158
159 internal func decode<Target>(
160 _ type: Target.Type,
161 forKey key: StringCodingKey
162 ) throws -> Target where Target: Decodable {
163 let childContainer = try childContainer(for: key)
164 let lowLevelDecoder = LowLevelDecoder(container: childContainer)
165
166 return try lowLevelDecoder.decodeWithSpecialTreatment(as: type)
167 }
168
169 internal func decodeNil(forKey key: StringCodingKey) throws -> Bool {
170 let encodedKey = configuration.keyStrategy.encode(key, at: codingPath)
171
172 guard let childContainer = children[encodedKey.stringValue] else {
173 return true
174 }
175
176 switch childContainer {
177 case .multiValue:
178 return false
179 case let .singleValue(singleValueContainer):
180 return singleValueContainer.decodeNil()
181 }
182 }
183
184 internal func nestedContainer<NestedKey>(
185 keyedBy type: NestedKey.Type,
186 forKey key: StringCodingKey
187 ) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
188 switch try childContainer(for: key) {
189 case let .multiValue(multiValueContainer):
190 return KeyedDecodingContainer(multiValueContainer.wrapped())
191 case let .singleValue(singleValueContainer):
192 return KeyedDecodingContainer(singleValueContainer.wrapped())
193 }
194 }
195
196 internal func nestedUnkeyedContainer(forKey key: StringCodingKey) throws -> UnkeyedDecodingContainer {
197 switch try childContainer(for: key) {
198 case let .multiValue(multiValueContainer):
199 return multiValueContainer
200 case let .singleValue(singleValueContainer):
201 return singleValueContainer
202 }
203 }
204
205 internal func superDecoder() throws -> Decoder {
206 let key = StringCodingKey(stringValue: "super")
207
208 return try superDecoder(forKey: key)
209 }
210
211 internal func superDecoder(forKey key: StringCodingKey) throws -> Decoder {
212 let encodedKey = configuration.keyStrategy.encode(key, at: codingPath)
213
214 guard let childContainer = children[encodedKey.stringValue] else {
215 throw DecodingError.keyNotFound(key, .noValueAssociatedWithKey(at: nextCodingPath(appending: encodedKey)))
216 }
217
218 return LowLevelDecoder(container: childContainer)
219 }
220}
221
222// MARK: - SingleValueDecodingContainer
223
224extension DecodingContainer.MultiValue: SingleValueDecodingContainer {
225 // NO-OP
226}
227
228// MARK: - UnkeyedDecodingContainer Extension
229
230extension DecodingContainer.MultiValue: UnkeyedDecodingContainer {
231 // MARK: Internal Instance Interface
232
233 internal var count: Int? {
234 children.count
235 }
236
237 internal var isAtEnd: Bool {
238 endIndex < currentIndex
239 }
240
241 internal func decode(_ type: Bool.Type) throws -> Bool {
242 let nextCodingKey = nextDecodingKey()
243
244 return try decode(type, forKey: nextCodingKey)
245 }
246
247 internal func decode(_ type: Double.Type) throws -> Double {
248 let nextCodingKey = nextDecodingKey()
249
250 return try decode(type, forKey: nextCodingKey)
251 }
252
253 internal func decode(_ type: Float.Type) throws -> Float {
254 let nextCodingKey = nextDecodingKey()
255
256 return try decode(type, forKey: nextCodingKey)
257 }
258
259 internal func decode(_ type: Int.Type) throws -> Int {
260 let nextCodingKey = nextDecodingKey()
261
262 return try decode(type, forKey: nextCodingKey)
263 }
264
265 internal func decode(_ type: Int8.Type) throws -> Int8 {
266 let nextCodingKey = nextDecodingKey()
267
268 return try decode(type, forKey: nextCodingKey)
269 }
270
271 internal func decode(_ type: Int16.Type) throws -> Int16 {
272 let nextCodingKey = nextDecodingKey()
273
274 return try decode(type, forKey: nextCodingKey)
275 }
276
277 internal func decode(_ type: Int32.Type) throws -> Int32 {
278 let nextCodingKey = nextDecodingKey()
279
280 return try decode(type, forKey: nextCodingKey)
281 }
282
283 internal func decode(_ type: Int64.Type) throws -> Int64 {
284 let nextCodingKey = nextDecodingKey()
285
286 return try decode(type, forKey: nextCodingKey)
287 }
288
289 internal func decode(_ type: String.Type) throws -> String {
290 let nextCodingKey = nextDecodingKey()
291
292 return try decode(type, forKey: nextCodingKey)
293 }
294
295 internal func decode(_ type: UInt.Type) throws -> UInt {
296 let nextCodingKey = nextDecodingKey()
297
298 return try decode(type, forKey: nextCodingKey)
299 }
300
301 internal func decode(_ type: UInt8.Type) throws -> UInt8 {
302 let nextCodingKey = nextDecodingKey()
303
304 return try decode(type, forKey: nextCodingKey)
305 }
306
307 internal func decode(_ type: UInt16.Type) throws -> UInt16 {
308 let nextCodingKey = nextDecodingKey()
309
310 return try decode(type, forKey: nextCodingKey)
311 }
312
313 internal func decode(_ type: UInt32.Type) throws -> UInt32 {
314 let nextCodingKey = nextDecodingKey()
315
316 return try decode(type, forKey: nextCodingKey)
317 }
318
319 internal func decode(_ type: UInt64.Type) throws -> UInt64 {
320 let nextCodingKey = nextDecodingKey()
321
322 return try decode(type, forKey: nextCodingKey)
323 }
324
325 internal func decode<Target>(_ type: Target.Type) throws -> Target where Target: Decodable {
326 let nextCodingKey = nextDecodingKey()
327
328 return try decode(type, forKey: nextCodingKey)
329 }
330
331 internal func decodeNil() -> Bool {
332 let nextCodingKey = nextDecodingKey()
333
334 return (try? decodeNil(forKey: nextCodingKey)) ?? false
335 }
336
337 internal func nestedContainer<NestedKey>(
338 keyedBy type: NestedKey.Type
339 ) throws -> KeyedDecodingContainer<NestedKey> where NestedKey: CodingKey {
340 let nextCodingKey = nextDecodingKey()
341
342 return try nestedContainer(keyedBy: type, forKey: nextCodingKey)
343 }
344
345 internal func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer {
346 let nextCodingKey = nextDecodingKey()
347
348 return try nestedUnkeyedContainer(forKey: nextCodingKey)
349 }
350}