Skip to content

Commit d853dab

Browse files
authored
Update CodableProxy (#547)
1 parent cd78bcc commit d853dab

File tree

4 files changed

+624
-4
lines changed

4 files changed

+624
-4
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// CodableAttributedString.swift
3+
// OpenSwiftUICore
4+
//
5+
// Status: WIP
6+
7+
package import class Foundation.NSAttributedString
8+
package import struct Foundation.NSRange
9+
10+
package struct CodableAttributedString {
11+
package struct Range {
12+
package var extent: NSRange
13+
package var attributes: [NSAttributedString.Key: Any]
14+
}
15+
16+
package var base: NSAttributedString
17+
18+
package init(_ base: NSAttributedString) {
19+
self.base = base
20+
}
21+
}
22+
23+
extension CodableAttributedString: ProtobufMessage {
24+
package func encode(to encoder: inout ProtobufEncoder) throws {
25+
_openSwiftUIUnimplementedFailure()
26+
}
27+
28+
package init(from decoder: inout ProtobufDecoder) throws {
29+
_openSwiftUIUnimplementedFailure()
30+
}
31+
}
32+
33+
extension CodableAttributedString.Range: ProtobufMessage {
34+
package func encode(to encoder: inout ProtobufEncoder) throws {
35+
_openSwiftUIUnimplementedFailure()
36+
}
37+
38+
package init(from decoder: inout ProtobufDecoder) throws {
39+
_openSwiftUIUnimplementedFailure()
40+
}
41+
}

Sources/OpenSwiftUICore/Data/Codable/CodableProxy.swift

Lines changed: 284 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,27 @@
22
// CodableProxy.swift
33
// OpenSwiftUICore
44
//
5-
// Audited for 6.0.87
6-
// Status: WIP
5+
// Audited for 6.5.4
6+
// Status: Complete
7+
// ID: A66FCB65C49D586C0CA23AF611BF2C2B (SwiftUICore?)
8+
9+
package import Foundation
10+
11+
// MARK: - CodableByProxy
712

813
package protocol CodableByProxy {
914
associatedtype CodingProxy: Codable
15+
1016
var codingProxy: CodingProxy { get }
1117

1218
static func unwrap(codingProxy: CodingProxy) -> Self
1319
}
1420

21+
// MARK: - CodableProxy
22+
1523
package protocol CodableProxy: Codable {
1624
associatedtype Base
25+
1726
var base: Base { get }
1827
}
1928

@@ -22,3 +31,276 @@ extension CodableByProxy where Self == CodingProxy.Base, CodingProxy: CodablePro
2231
codingProxy.base
2332
}
2433
}
34+
35+
// MARK: - ProxyCodable
36+
37+
@propertyWrapper
38+
package struct ProxyCodable<Value>: Codable where Value: CodableByProxy {
39+
package var wrappedValue: Value
40+
41+
package var projectedValue: ProxyCodable<Value> { self }
42+
43+
package init(_ value: Value) {
44+
self.wrappedValue = value
45+
}
46+
47+
package init(wrappedValue: Value) {
48+
self.wrappedValue = wrappedValue
49+
}
50+
51+
package func encode(to encoder: any Encoder) throws {
52+
var container = encoder.singleValueContainer()
53+
try container.encode(wrappedValue.codingProxy)
54+
}
55+
56+
package init(from decoder: any Decoder) throws {
57+
var container = try decoder.singleValueContainer()
58+
let proxy = try container.decode(Value.CodingProxy.self)
59+
wrappedValue = Value.unwrap(codingProxy: proxy)
60+
}
61+
}
62+
63+
extension ProxyCodable: Equatable where Value: Equatable {
64+
package static func == (lhs: ProxyCodable<Value>, rhs: ProxyCodable<Value>) -> Bool {
65+
lhs.wrappedValue == rhs.wrappedValue
66+
}
67+
}
68+
69+
extension ProxyCodable: Hashable where Value: Hashable {
70+
package func hash(into hasher: inout Hasher) {
71+
hasher.combine(wrappedValue)
72+
}
73+
}
74+
75+
// MARK: - Optional + CodableByProxy
76+
77+
extension Optional: CodableByProxy where Wrapped: CodableByProxy {
78+
package var codingProxy: CodableOptional<Wrapped> {
79+
CodableOptional(self)
80+
}
81+
}
82+
83+
// MARK: - RawRepresentable + CodableByProxy
84+
85+
extension RawRepresentable where RawValue: Codable {
86+
package var codingProxy: RawRepresentableProxy<Self> {
87+
RawRepresentableProxy(self)
88+
}
89+
}
90+
91+
// MARK: - Error
92+
93+
private enum Error: Swift.Error {
94+
case unarchivingError
95+
}
96+
97+
// MARK: - RawRepresentableProxy
98+
99+
package struct RawRepresentableProxy<Value>: CodableProxy where Value: RawRepresentable, Value.RawValue: Codable {
100+
package var base: Value
101+
102+
package init(_ base: Value) {
103+
self.base = base
104+
}
105+
106+
package init(from decoder: any Decoder) throws {
107+
let container = try decoder.singleValueContainer()
108+
let rawValue = try container.decode(Value.RawValue.self)
109+
guard let value = Value(rawValue: rawValue) else {
110+
throw Error.unarchivingError
111+
}
112+
base = value
113+
}
114+
115+
package func encode(to encoder: any Encoder) throws {
116+
var container = encoder.singleValueContainer()
117+
try container.encode(base.rawValue)
118+
}
119+
}
120+
121+
// MARK: - NSAttributedString.Key + CodableByProxy
122+
123+
extension NSAttributedString.Key: CodableByProxy {
124+
package typealias CodingProxy = RawRepresentableProxy<NSAttributedString.Key>
125+
}
126+
127+
// MARK: - Array + CodableByProxy
128+
129+
extension Array: CodableByProxy where Element: CodableByProxy {
130+
package var codingProxy: [Element.CodingProxy] {
131+
map(\.codingProxy)
132+
}
133+
134+
package static func unwrap(codingProxy: [Element.CodingProxy]) -> [Element] {
135+
codingProxy.map { Element.unwrap(codingProxy: $0) }
136+
}
137+
}
138+
139+
// MARK: - JSONCodable
140+
141+
package struct JSONCodable<Value>: Codable {
142+
package var base: Value
143+
144+
package init(_ base: Value) {
145+
self.base = base
146+
}
147+
148+
package func encode(to encoder: any Encoder) throws {
149+
let data = try JSONSerialization.data(withJSONObject: base)
150+
let string = String(data: data, encoding: .utf8)!
151+
var container = encoder.singleValueContainer()
152+
try container.encode(string)
153+
}
154+
155+
private enum Error: Swift.Error {
156+
case invalidType(objectDescription: String, dataDescription: String)
157+
}
158+
159+
package init(from decoder: any Decoder) throws {
160+
let container = try decoder.singleValueContainer()
161+
let string = try container.decode(String.self)
162+
let data = string.data(using: .utf8)!
163+
let object = try JSONSerialization.jsonObject(with: data)
164+
guard let base = object as? Value else {
165+
throw Error.invalidType(
166+
objectDescription: String(describing: type(of: object)),
167+
dataDescription: string
168+
)
169+
}
170+
self.base = base
171+
}
172+
}
173+
174+
// MARK: - CodableRawRepresentable
175+
176+
@propertyWrapper
177+
package struct CodableRawRepresentable<Value>: Codable where Value: RawRepresentable, Value.RawValue: Codable {
178+
package var wrappedValue: Value
179+
180+
package init(_ value: Value) {
181+
self.wrappedValue = value
182+
}
183+
184+
package init(wrappedValue: Value) {
185+
self.wrappedValue = wrappedValue
186+
}
187+
188+
package init(from decoder: any Decoder) throws {
189+
let container = try decoder.singleValueContainer()
190+
let rawValue = try container.decode(Value.RawValue.self)
191+
guard let value = Value(rawValue: rawValue) else {
192+
throw Error.unarchivingError
193+
}
194+
wrappedValue = value
195+
}
196+
197+
package func encode(to encoder: any Encoder) throws {
198+
var container = encoder.singleValueContainer()
199+
try container.encode(wrappedValue.rawValue)
200+
}
201+
}
202+
203+
extension CodableRawRepresentable: Equatable where Value: Equatable {
204+
package static func == (lhs: CodableRawRepresentable<Value>, rhs: CodableRawRepresentable<Value>) -> Bool {
205+
lhs.wrappedValue == rhs.wrappedValue
206+
}
207+
}
208+
209+
extension CodableRawRepresentable: Hashable where Value: Hashable {
210+
package func hash(into hasher: inout Hasher) {
211+
hasher.combine(wrappedValue)
212+
}
213+
}
214+
215+
// MARK: - CodableOptional
216+
217+
package struct CodableOptional<Wrapped>: CodableProxy where Wrapped: CodableByProxy {
218+
package var base: Wrapped?
219+
220+
package init(_ base: Wrapped?) {
221+
self.base = base
222+
}
223+
224+
private enum CodingKeys: CodingKey {
225+
case value
226+
}
227+
228+
package func encode(to encoder: any Encoder) throws {
229+
var container = encoder.container(keyedBy: CodingKeys.self)
230+
if let base {
231+
try container.encode(base.codingProxy, forKey: .value)
232+
}
233+
}
234+
235+
package init(from decoder: any Decoder) throws {
236+
let container = try decoder.container(keyedBy: CodingKeys.self)
237+
let proxy = try container.decodeIfPresent(Wrapped.CodingProxy.self, forKey: .value)
238+
base = proxy.map { Wrapped.unwrap(codingProxy: $0) }
239+
}
240+
}
241+
242+
// MARK: - CodableNSAttributes
243+
244+
@propertyWrapper
245+
package struct CodableNSAttributes: CodableByProtobuf, Hashable {
246+
247+
package typealias Value = [NSAttributedString.Key: Any]
248+
249+
package var wrappedValue: Value
250+
251+
package var projectedValue: CodableNSAttributes { self }
252+
253+
package init(_ value: Value) {
254+
self.wrappedValue = value
255+
}
256+
257+
package init(wrappedValue: Value) {
258+
self.wrappedValue = wrappedValue
259+
}
260+
261+
package func encode(to encoder: inout ProtobufEncoder) throws {
262+
let string = NSAttributedString(string: " ", attributes: wrappedValue)
263+
try CodableAttributedString(string).encode(to: &encoder)
264+
}
265+
266+
package init(from decoder: inout ProtobufDecoder) throws {
267+
let string = try CodableAttributedString(from: &decoder).base
268+
guard string.length >= 0 else {
269+
throw DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "CodableNSAttribute found empty string"))
270+
}
271+
wrappedValue = string.attributes(at: 0, effectiveRange: nil)
272+
}
273+
274+
package static func == (lhs: CodableNSAttributes, rhs: CodableNSAttributes) -> Bool {
275+
func areEqual<T>(_ a: T, _ b: Any) -> Bool where T: Equatable {
276+
guard let b = b as? T else {
277+
return false
278+
}
279+
return a == b
280+
}
281+
guard lhs.wrappedValue.count == rhs.wrappedValue.count else {
282+
return false
283+
}
284+
for (key, leftValue) in lhs.wrappedValue {
285+
guard let rightValue = rhs.wrappedValue[key] else {
286+
return false
287+
}
288+
guard let leftValue = leftValue as? any Equatable else {
289+
return false
290+
}
291+
guard areEqual(leftValue, rightValue) else {
292+
return false
293+
}
294+
}
295+
return true
296+
}
297+
298+
package func hash(into hasher: inout Hasher) {
299+
for (key, value) in wrappedValue {
300+
hasher.combine(key)
301+
if let value = value as? any Hashable {
302+
hasher.combine(value)
303+
}
304+
}
305+
}
306+
}

Sources/OpenSwiftUICore/Data/Protobuf/ProtobufMessage.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ package enum ProtobufFormat {
144144
// MARK: - CoddleByProtobuf
145145

146146
/// A type that can be encoded and decoded using protobuf.
147-
package protocol CodaleByProtobuf: Codable, ProtobufMessage {}
147+
package protocol CodableByProtobuf: Codable, ProtobufMessage {}
148148

149-
extension CodaleByProtobuf {
149+
extension CodableByProtobuf {
150150
/// Encodes the value to a protobuf representation.
151151
public func encode(to encoder: any Encoder) throws {
152152
let data = try ProtobufEncoder.encoding { protobufEncoder in

0 commit comments

Comments
 (0)