Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
5.7 kB · 148 lines
Swift
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149//// URLQueryItemEncoder.swift// URLQueryItemCoder//// Created by Kyle Hughes on 1/15/23.//
import Foundation
/// An object that encodes instances of a data type as `URLQueryItem` name-value pairs.public struct URLQueryItemEncoder { /// The strategies used by this encoder for encoding `Encodable` values. public var strategies: EncodingStrategies /// The formatting settings used on the output of the encoder. public var outputFormatting: OutputFormatting // MARK: Public Initialization /// Creates a new, reusable `URLQueryItem` encoder. /// /// The default formatting settings and encoding strategies are used if none are supplied. /// /// - Parameter dataStrategy: The strategy to use for encoding `Data` values. /// - Parameter dateStrategy: The strategy to use for encoding `Date` values. /// - Parameter keyStrategy: The strategy to use for encoding keys on keyed containers. /// - Parameter nonConformingFloatStrategy: The strategy to use for encoding non-`URLQueryItem`-conforming /// floating-point values (IEEE 754 infinity and NaN). /// - Parameter outputFormatting: The formatting settings used on the output of the encoder. /// - Returns: A new, reusable `URLQueryItem` encoder. @inlinable public init( arrayStrategy: ArrayEncodingStrategy = .default, dataStrategy: DataEncodingStrategy = .default, dateStrategy: DateEncodingStrategy = .default, keyStrategy: KeyEncodingStrategy = .default, nonConformingFloatStrategy: NonConformingFloatEncodingStrategy = .default, outputFormatting: OutputFormatting = .default ) { self.init( strategies: EncodingStrategies( arrayStrategy: arrayStrategy, dataStrategy: dataStrategy, dateStrategy: dateStrategy, keyStrategy: keyStrategy, nonConformingFloatStrategy: nonConformingFloatStrategy ), outputFormatting: outputFormatting ) } /// Creates a new, reusable `URLQueryItem` encoder. /// /// The default formatting settings and encoding strategies are used if none are supplied. /// /// - Parameter strategies: The strategies for this encoder to use. The default value is `.default`. /// - Parameter outputFormatting: The formatting settings used on the output of the encoder. /// - Returns: A new, reusable `URLQueryItem` encoder. public init(strategies: EncodingStrategies, outputFormatting: OutputFormatting = .default) { self.strategies = strategies self.outputFormatting = outputFormatting } // MARK: Private Instance Interface
private func encode( _ container: EncodingContainer?, at key: String = String(), into queryItems: inout [URLQueryItem] ) { guard let container else { return }
let separator = key.isEmpty ? "" : "."
switch container { case let .keyed(keyedContainer): if keyedContainer.children.isEmpty { if !key.isEmpty { queryItems.append(URLQueryItem(name: key, value: String())) } } else { for (subKey, childContainer) in keyedContainer.children { let nextKey = "\(key)\(separator)\(subKey)" encode(childContainer, at: nextKey, into: &queryItems) } } case let .lowLevelEncoder(lowLevelEncoder): guard let childContainer = lowLevelEncoder.container else { preconditionFailure("Nothing was never encoded to nested low level encoder.") } encode(childContainer, at: key, into: &queryItems) case let .singleValue(singleValueContainer): switch singleValueContainer.storage { case let .container(childContainer): encode(childContainer, at: key, into: &queryItems) case let .primitive(value): if !key.isEmpty || value != nil { queryItems.append(URLQueryItem(name: key, value: value.map { String(describing: $0) })) } case .none: preconditionFailure("Value was never encoded to single value container.") } case let .unkeyed(unkeyedContainer): for (index, childContainer) in unkeyedContainer.children.enumerated() { switch strategies.arrayStrategy { case .indexed: let nextKey = "\(key)\(separator)\(index)" encode(childContainer, at: nextKey, into: &queryItems) case .repeated: encode(childContainer, at: key, into: &queryItems) } } } }}
extension URLQueryItemEncoder { // MARK: Public Instance Interface
/// Encodes an instance of the indicated type. /// /// - Parameter value: The instance to encode. /// - Returns: The query items that represent the given value. public func encode(_ value: some Encodable) throws -> [URLQueryItem] { let container = try EncodingContainer.encodeWithSpecialTreatment(value, at: [], using: strategies)
var queryItems: [URLQueryItem] = []
encode(container, into: &queryItems)
if outputFormatting.contains(.sortedKeys) { return queryItems.sorted { $0.name < $1.name } } else { return queryItems } }}
// MARK: - TopLevelEncoder Extension#if canImport(Combine)import Combineextension URLQueryItemEncoder: TopLevelEncoder {}#endif