|
| 1 | +// |
| 2 | +// APIParameterConvertible.swift |
| 3 | +// RaAPIWrapper |
| 4 | +// |
| 5 | +// Created by Rakuyo on 2022/8/25. |
| 6 | +// Copyright © 2022 Rakuyo. All rights reserved. |
| 7 | +// |
| 8 | + |
| 9 | +import Foundation |
| 10 | + |
| 11 | +/// Means that the type can be converted to an interface parameter for requesting an api. |
| 12 | +protocol APIParameterConvertible { |
| 13 | + /// Converts the target to an Encodable-compliant type. |
| 14 | + var toParameters: AnyAPIParameter { get } |
| 15 | +} |
| 16 | + |
| 17 | +// MARK: - Array |
| 18 | + |
| 19 | +extension Array: APIParameterConvertible { |
| 20 | + /// For `[AnyObject]` arrays, or a mixed array with very complex elements. |
| 21 | + var toParameters: AnyAPIParameter { |
| 22 | + let filtered = (self as [Any?]).compactMap { $0 } |
| 23 | + |
| 24 | + let result: [AnyAPIParameter] = filtered.compactMap { |
| 25 | + if let value = $0 as? AnyAPIParameter { return value } |
| 26 | + if let value = $0 as? (any APIParameter) { return .init(value) } |
| 27 | + if let value = $0 as? APIParameterConvertible { return value.toParameters } |
| 28 | + return mapAnyObjectToEncodable($0 as AnyObject) |
| 29 | + } |
| 30 | + |
| 31 | + assert(filtered.count == result.count, "There are elements in the container type that are not nil that cannot be converted to AnyAPIParameter type. This behavior will cause the parameter to be discarded and not sent to the server. This behavior is usually dangerous and needs to be fixed, please check your code!") |
| 32 | + |
| 33 | + return .init(result) |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +// MARK: - Dictionary |
| 38 | + |
| 39 | +extension Dictionary: APIParameterConvertible where Key == String { |
| 40 | + /// For a `[String: AnyObject]` dictionary, or a mixed dictionary with very complex elements. |
| 41 | + var toParameters: AnyAPIParameter { |
| 42 | + let filtered = (self as [String: Any?]).compactMapValues { $0 } |
| 43 | + |
| 44 | + let result: [String: AnyAPIParameter] = filtered.compactMapValues { |
| 45 | + if let value = $0 as? AnyAPIParameter { return value } |
| 46 | + if let value = $0 as? (any APIParameter) { return .init(value) } |
| 47 | + if let value = $0 as? APIParameterConvertible { return value.toParameters } |
| 48 | + return mapAnyObjectToEncodable($0 as AnyObject) |
| 49 | + } |
| 50 | + |
| 51 | + assert(filtered.count == result.count, "There are elements in the container type that are not nil that cannot be converted to AnyAPIParameter type. This behavior will cause the parameter to be discarded and not sent to the server. This behavior is usually dangerous and needs to be fixed, please check your code!") |
| 52 | + |
| 53 | + return .init(result) |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +// MARK: - Tools |
| 58 | + |
| 59 | +private extension APIParameterConvertible { |
| 60 | + func mapAnyObjectToEncodable(_ value: AnyObject) -> AnyAPIParameter? { |
| 61 | + if let result = value as? String { return .init(result) } |
| 62 | + if let result = value as? Character { return .init(String(result)) } |
| 63 | + if let result = value as? Int { return .init(result) } |
| 64 | + if let result = value as? UInt { return .init(result) } |
| 65 | + if let result = value as? Double { return .init(result) } |
| 66 | + if let result = value as? Float { return .init(result) } |
| 67 | + if let result = value as? Bool { return .init(result) } |
| 68 | + if let result = value as? Data { return .init(result) } |
| 69 | + if let result = value as? Date { return .init(result) } |
| 70 | + if let result = value as? [String: Any] { return result.toParameters } |
| 71 | + if let result = value as? [Any] { return result.toParameters } |
| 72 | + |
| 73 | + return nil |
| 74 | + } |
| 75 | +} |
0 commit comments