-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathURLQueryEncoder.swift
More file actions
133 lines (106 loc) · 5.04 KB
/
URLQueryEncoder.swift
File metadata and controls
133 lines (106 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import Foundation
public final class URLQueryEncoder: Sendable {
public static let `default` = URLQueryEncoder()
private let optionsMutex: Mutex<URLQueryEncodingOptions>
private let userInfoMutex: Mutex<[CodingUserInfoKey: Sendable]>
public var dateEncodingStrategy: URLQueryDateEncodingStrategy {
get { optionsMutex.withLock { $0.dateEncodingStrategy } }
set { optionsMutex.withLock { $0.dateEncodingStrategy = newValue } }
}
public var dataEncodingStrategy: URLQueryDataEncodingStrategy {
get { optionsMutex.withLock { $0.dataEncodingStrategy } }
set { optionsMutex.withLock { $0.dataEncodingStrategy = newValue } }
}
public var nonConformingFloatEncodingStrategy: URLQueryNonConformingFloatEncodingStrategy {
get { optionsMutex.withLock { $0.nonConformingFloatEncodingStrategy } }
set { optionsMutex.withLock { $0.nonConformingFloatEncodingStrategy = newValue } }
}
public var boolEncodingStrategy: URLQueryBoolEncodingStrategy {
get { optionsMutex.withLock { $0.boolEncodingStrategy } }
set { optionsMutex.withLock { $0.boolEncodingStrategy = newValue } }
}
public var arrayEncodingStrategy: URLQueryArrayEncodingStrategy {
get { optionsMutex.withLock { $0.arrayEncodingStrategy } }
set { optionsMutex.withLock { $0.arrayEncodingStrategy = newValue } }
}
public var spaceEncodingStrategy: URLQuerySpaceEncodingStrategy {
get { optionsMutex.withLock { $0.spaceEncodingStrategy } }
set { optionsMutex.withLock { $0.spaceEncodingStrategy = newValue } }
}
public var keyEncodingStrategy: URLQueryKeyEncodingStrategy {
get { optionsMutex.withLock { $0.keyEncodingStrategy } }
set { optionsMutex.withLock { $0.keyEncodingStrategy = newValue } }
}
public var userInfo: [CodingUserInfoKey: Sendable] {
get { userInfoMutex.withLock { $0 } }
set { userInfoMutex.withLock { $0 = newValue } }
}
public init(
dateEncodingStrategy: URLQueryDateEncodingStrategy = .deferredToDate,
dataEncodingStrategy: URLQueryDataEncodingStrategy = .base64,
nonConformingFloatEncodingStrategy: URLQueryNonConformingFloatEncodingStrategy = .throw,
boolEncodingStrategy: URLQueryBoolEncodingStrategy = .literal,
arrayEncodingStrategy: URLQueryArrayEncodingStrategy = .enumerated,
spaceEncodingStrategy: URLQuerySpaceEncodingStrategy = .percentEscaped,
keyEncodingStrategy: URLQueryKeyEncodingStrategy = .useDefaultKeys,
userInfo: [CodingUserInfoKey: Sendable] = [:]
) {
let options = URLQueryEncodingOptions(
dateEncodingStrategy: dateEncodingStrategy,
dataEncodingStrategy: dataEncodingStrategy,
nonConformingFloatEncodingStrategy: nonConformingFloatEncodingStrategy,
boolEncodingStrategy: boolEncodingStrategy,
arrayEncodingStrategy: arrayEncodingStrategy,
spaceEncodingStrategy: spaceEncodingStrategy,
keyEncodingStrategy: keyEncodingStrategy
)
self.optionsMutex = Mutex(value: options)
self.userInfoMutex = Mutex(value: userInfo)
}
public func encode<T: Encodable>(_ value: T) throws -> String {
let options = optionsMutex.withLock { $0 }
let encoder = URLQuerySingleValueEncodingContainer(
options: options,
userInfo: userInfo,
codingPath: []
)
try value.encode(to: encoder)
guard case let .dictionary(urlEncodedForm) = encoder.resolveValue() else {
let errorContext = EncodingError.Context(
codingPath: [],
debugDescription: "Root component cannot be encoded in URL"
)
throw EncodingError.invalidValue(value, errorContext)
}
let serializer = URLQuerySerializer(
arrayEncodingStrategy: arrayEncodingStrategy,
spaceEncodingStrategy: spaceEncodingStrategy
)
return serializer.serialize(urlEncodedForm)
}
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)
public func encode<T: EncodableWithConfiguration>(
_ value: T,
configuration: T.EncodingConfiguration
) throws -> String {
let options = optionsMutex.withLock { $0 }
let encoder = URLQuerySingleValueEncodingContainer(
options: options,
userInfo: userInfo,
codingPath: []
)
try value.encode(to: encoder, configuration: configuration)
guard case let .dictionary(urlEncodedForm) = encoder.resolveValue() else {
let errorContext = EncodingError.Context(
codingPath: [],
debugDescription: "Root component cannot be encoded in URL"
)
throw EncodingError.invalidValue(value, errorContext)
}
let serializer = URLQuerySerializer(
arrayEncodingStrategy: arrayEncodingStrategy,
spaceEncodingStrategy: spaceEncodingStrategy
)
return serializer.serialize(urlEncodedForm)
}
}