Skip to content

Commit 9bed481

Browse files
authored
Add Foundation ProtobufMessage conformances (URL, UUID, Data, Locale) (#804)
1 parent fd30b84 commit 9bed481

6 files changed

Lines changed: 332 additions & 21 deletions

File tree

Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 1 addition & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/SharedExample/ContentView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ import SwiftUI
1313

1414
struct ContentView: View {
1515
var body: some View {
16-
FlowerView()
16+
Image(systemName: "gear")
1717
}
1818
}

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ let releaseVersion = envIntValue("TARGET_RELEASE", default: 2024)
145145
let libraryEvolutionCondition = envBoolValue("LIBRARY_EVOLUTION", default: buildForDarwinPlatform)
146146
let compatibilityTestCondition = envBoolValue("COMPATIBILITY_TEST")
147147

148-
let useLocalDeps = envBoolValue("USE_LOCAL_DEPS")
148+
let useLocalDeps = envBoolValue("USE_LOCAL_DEPS", default: true)
149149

150150
// For OpenAttributeGraphShims
151151
let computeCondition = envBoolValue("OPENATTRIBUTESHIMS_COMPUTE", default: false)
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//
2+
// Foundation+ProtobufMessage.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for 6.5.4
6+
// Status: WIP
7+
// Note: Data archiveWriter/archiveReader deduplication not yet implemented
8+
9+
package import Foundation
10+
11+
// MARK: - URL + ProtobufMessage
12+
13+
extension URL: ProtobufMessage {
14+
package func encode(to encoder: inout ProtobufEncoder) throws {
15+
try encoder.stringField(1, relativeString)
16+
if let baseURL {
17+
try encoder.messageField(2, baseURL)
18+
}
19+
}
20+
21+
package init(from decoder: inout ProtobufDecoder) throws {
22+
var relativeString = ""
23+
var baseURL: URL? = nil
24+
while let field = try decoder.nextField() {
25+
switch field.tag {
26+
case 1: relativeString = try decoder.stringField(field)
27+
case 2: baseURL = try decoder.messageField(field)
28+
default: try decoder.skipField(field)
29+
}
30+
}
31+
guard let url = URL(string: relativeString, relativeTo: baseURL) else {
32+
throw ProtobufDecoder.DecodingError.failed
33+
}
34+
self = url
35+
}
36+
}
37+
38+
// MARK: - UUID + ProtobufMessage
39+
40+
extension UUID: ProtobufMessage {
41+
package func encode(to encoder: inout ProtobufEncoder) throws {
42+
withUnsafeBytes(of: uuid) { buffer in
43+
encoder.dataField(1, buffer)
44+
}
45+
}
46+
47+
package init(from decoder: inout ProtobufDecoder) throws {
48+
var uuidBytes: uuid_t = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
49+
while let field = try decoder.nextField() {
50+
switch field.tag {
51+
case 1:
52+
let buffer = try decoder.dataBufferField(field)
53+
guard buffer.count == 16, let src = buffer.baseAddress else {
54+
throw ProtobufDecoder.DecodingError.failed
55+
}
56+
withUnsafeMutableBytes(of: &uuidBytes) { $0.baseAddress!.copyMemory(from: src, byteCount: 16) }
57+
default:
58+
try decoder.skipField(field)
59+
}
60+
}
61+
self = UUID(uuid: uuidBytes)
62+
}
63+
}
64+
65+
// MARK: - Data + ProtobufMessage [WIP]
66+
67+
extension Data: ProtobufMessage {
68+
package func encode(to encoder: inout ProtobufEncoder) throws {
69+
if /*let archiveWriter*/ false {
70+
// TODO
71+
_openSwiftUIUnreachableCode()
72+
} else {
73+
encoder.dataField(2, self)
74+
}
75+
}
76+
77+
package init(from decoder: inout ProtobufDecoder) throws {
78+
self = Data()
79+
while let field = try decoder.nextField() {
80+
switch field.tag {
81+
case 2:
82+
self = try decoder.dataField(field)
83+
default:
84+
try decoder.skipField(field)
85+
}
86+
}
87+
}
88+
}
89+
90+
// MARK: - Locale + ProtobufMessage
91+
92+
extension Locale: ProtobufMessage {
93+
package func encode(to encoder: inout ProtobufEncoder) throws {
94+
try encoder.stringField(1, identifier)
95+
}
96+
97+
package init(from decoder: inout ProtobufDecoder) throws {
98+
var identifier = ""
99+
while let field = try decoder.nextField() {
100+
switch field.tag {
101+
case 1: identifier = try decoder.stringField(field)
102+
default: try decoder.skipField(field)
103+
}
104+
}
105+
self = Locale(identifier: identifier)
106+
}
107+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// FoundationProtobufMessageTestsStub.c
3+
// OpenSwiftUISymbolDualTestsSupport
4+
5+
#include "OpenSwiftUIBase.h"
6+
7+
#if OPENSWIFTUI_TARGET_OS_DARWIN
8+
#import <SymbolLocator.h>
9+
10+
// URL
11+
DEFINE_SL_STUB_SLF(OpenSwiftUITestStub_URLEncode, SwiftUICore, $s10Foundation3URLV7SwiftUIE6encode2toyAD15ProtobufEncoderVz_tKF);
12+
DEFINE_SL_STUB_SLF(OpenSwiftUITestStub_URLDecode, SwiftUICore, $s10Foundation3URLV7SwiftUIE4fromAcD15ProtobufDecoderVz_tKcfC);
13+
14+
// UUID
15+
DEFINE_SL_STUB_SLF(OpenSwiftUITestStub_UUIDEncode, SwiftUICore, $s10Foundation4UUIDV7SwiftUIE6encode2toyAD15ProtobufEncoderVz_tKF);
16+
DEFINE_SL_STUB_SLF(OpenSwiftUITestStub_UUIDDecode, SwiftUICore, $s10Foundation4UUIDV7SwiftUIE4fromAcD15ProtobufDecoderVz_tKcfC);
17+
18+
// Data
19+
DEFINE_SL_STUB_SLF(OpenSwiftUITestStub_DataEncode, SwiftUICore, $s10Foundation4DataV7SwiftUIE6encode2toyAD15ProtobufEncoderVz_tKF);
20+
DEFINE_SL_STUB_SLF(OpenSwiftUITestStub_DataDecode, SwiftUICore, $s10Foundation4DataV7SwiftUIE4fromAcD15ProtobufDecoderVz_tKcfC);
21+
22+
// Locale
23+
DEFINE_SL_STUB_SLF(OpenSwiftUITestStub_LocaleEncode, SwiftUICore, $s10Foundation6LocaleV7SwiftUIE6encode2toyAD15ProtobufEncoderVz_tKF);
24+
DEFINE_SL_STUB_SLF(OpenSwiftUITestStub_LocaleDecode, SwiftUICore, $s10Foundation6LocaleV7SwiftUIE4fromAcD15ProtobufDecoderVz_tKcfC);
25+
26+
#endif
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
//
2+
// FoundationProtobufMessageDualTests.swift
3+
// OpenSwiftUISymbolDualTests
4+
5+
#if canImport(SwiftUI, _underlyingVersion: 6.5.4)
6+
import Foundation
7+
import OpenSwiftUICore
8+
import OpenSwiftUITestsSupport
9+
import Testing
10+
11+
// MARK: - @_silgen_name declarations
12+
13+
extension URL {
14+
@_silgen_name("OpenSwiftUITestStub_URLEncode")
15+
func swiftUI_encode(to encoder: inout ProtobufEncoder) throws
16+
17+
@_silgen_name("OpenSwiftUITestStub_URLDecode")
18+
init(swiftUI_from decoder: inout ProtobufDecoder) throws
19+
}
20+
21+
extension UUID {
22+
@_silgen_name("OpenSwiftUITestStub_UUIDEncode")
23+
func swiftUI_encode(to encoder: inout ProtobufEncoder) throws
24+
25+
@_silgen_name("OpenSwiftUITestStub_UUIDDecode")
26+
init(swiftUI_from decoder: inout ProtobufDecoder) throws
27+
}
28+
29+
extension Data {
30+
@_silgen_name("OpenSwiftUITestStub_DataEncode")
31+
func swiftUI_encode(to encoder: inout ProtobufEncoder) throws
32+
33+
@_silgen_name("OpenSwiftUITestStub_DataDecode")
34+
init(swiftUI_from decoder: inout ProtobufDecoder) throws
35+
}
36+
37+
extension Locale {
38+
@_silgen_name("OpenSwiftUITestStub_LocaleEncode")
39+
func swiftUI_encode(to encoder: inout ProtobufEncoder) throws
40+
41+
@_silgen_name("OpenSwiftUITestStub_LocaleDecode")
42+
init(swiftUI_from decoder: inout ProtobufDecoder) throws
43+
}
44+
45+
// MARK: - Tests
46+
47+
@Suite
48+
struct FoundationProtobufMessageDualTests {
49+
@Suite
50+
struct URLTests {
51+
@Test(
52+
arguments: [
53+
(
54+
URL(string: "https://example.com")!,
55+
"0a1368747470733a2f2f6578616d706c652e636f6d"
56+
),
57+
(
58+
URL(string: "path", relativeTo: URL(string: "https://example.com"))!,
59+
"0a04706174681215 0a1368747470733a2f2f6578616d706c652e636f6d"
60+
.replacingOccurrences(of: " ", with: "")
61+
),
62+
]
63+
)
64+
func pbMessage(url: URL, hexString: String) throws {
65+
try url.testPBEncoding(hexString: hexString)
66+
try url.testPBDecoding(hexString: hexString)
67+
try url.testPBEncoding(swiftUI_hexString: hexString)
68+
try url.testPBDecoding(swiftUI_hexString: hexString)
69+
}
70+
}
71+
72+
@Suite
73+
struct UUIDTests {
74+
@Test(
75+
arguments: [
76+
(
77+
UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E5F")!,
78+
"0a10e621e1f8c36c495a93fc0c247a3e6e5f"
79+
),
80+
]
81+
)
82+
func pbMessage(uuid: UUID, hexString: String) throws {
83+
try uuid.testPBEncoding(hexString: hexString)
84+
try uuid.testPBDecoding(hexString: hexString)
85+
try uuid.testPBEncoding(swiftUI_hexString: hexString)
86+
try uuid.testPBDecoding(swiftUI_hexString: hexString)
87+
}
88+
}
89+
90+
@Suite
91+
struct DataTests {
92+
@Test(
93+
arguments: [
94+
(Data(), ""),
95+
(Data([0x48, 0x65, 0x6c, 0x6c, 0x6f]), "120548656c6c6f"),
96+
]
97+
)
98+
func pbMessage(data: Data, hexString: String) throws {
99+
try data.testPBEncoding(hexString: hexString)
100+
try data.testPBDecoding(hexString: hexString)
101+
try data.testPBEncoding(swiftUI_hexString: hexString)
102+
try data.testPBDecoding(swiftUI_hexString: hexString)
103+
}
104+
}
105+
106+
@Suite
107+
struct LocaleTests {
108+
@Test(
109+
arguments: [
110+
(Locale(identifier: "en_US"), "0a05656e5f5553"),
111+
]
112+
)
113+
func pbMessage(locale: Locale, hexString: String) throws {
114+
try locale.testPBEncoding(hexString: hexString)
115+
try locale.testPBDecoding(hexString: hexString)
116+
try locale.testPBEncoding(swiftUI_hexString: hexString)
117+
try locale.testPBDecoding(swiftUI_hexString: hexString)
118+
}
119+
}
120+
}
121+
122+
// MARK: - SwiftUI Dual Test Helpers
123+
124+
extension URL {
125+
func testPBEncoding(swiftUI_hexString expectedHexString: String) throws {
126+
let data = try ProtobufEncoder.encoding { encoder in
127+
try swiftUI_encode(to: &encoder)
128+
}
129+
#expect(data.hexString == expectedHexString)
130+
}
131+
132+
func testPBDecoding(swiftUI_hexString hexString: String) throws {
133+
guard let data = Data(hexString: hexString) else {
134+
throw ProtobufDecoder.DecodingError.failed
135+
}
136+
var decoder = ProtobufDecoder(data)
137+
let decoded = try URL(swiftUI_from: &decoder)
138+
#expect(decoded == self)
139+
}
140+
}
141+
142+
extension UUID {
143+
func testPBEncoding(swiftUI_hexString expectedHexString: String) throws {
144+
let data = try ProtobufEncoder.encoding { encoder in
145+
try swiftUI_encode(to: &encoder)
146+
}
147+
#expect(data.hexString == expectedHexString)
148+
}
149+
150+
func testPBDecoding(swiftUI_hexString hexString: String) throws {
151+
guard let data = Data(hexString: hexString) else {
152+
throw ProtobufDecoder.DecodingError.failed
153+
}
154+
var decoder = ProtobufDecoder(data)
155+
let decoded = try UUID(swiftUI_from: &decoder)
156+
#expect(decoded == self)
157+
}
158+
}
159+
160+
extension Data {
161+
func testPBEncoding(swiftUI_hexString expectedHexString: String) throws {
162+
let data = try ProtobufEncoder.encoding { encoder in
163+
try swiftUI_encode(to: &encoder)
164+
}
165+
#expect(data.hexString == expectedHexString)
166+
}
167+
168+
func testPBDecoding(swiftUI_hexString hexString: String) throws {
169+
guard let data = Data(hexString: hexString) else {
170+
throw ProtobufDecoder.DecodingError.failed
171+
}
172+
var decoder = ProtobufDecoder(data)
173+
let decoded = try Data(swiftUI_from: &decoder)
174+
#expect(decoded == self)
175+
}
176+
}
177+
178+
extension Locale {
179+
func testPBEncoding(swiftUI_hexString expectedHexString: String) throws {
180+
let data = try ProtobufEncoder.encoding { encoder in
181+
try swiftUI_encode(to: &encoder)
182+
}
183+
#expect(data.hexString == expectedHexString)
184+
}
185+
186+
func testPBDecoding(swiftUI_hexString hexString: String) throws {
187+
guard let data = Data(hexString: hexString) else {
188+
throw ProtobufDecoder.DecodingError.failed
189+
}
190+
var decoder = ProtobufDecoder(data)
191+
let decoded = try Locale(swiftUI_from: &decoder)
192+
#expect(decoded == self)
193+
}
194+
}
195+
196+
#endif

0 commit comments

Comments
 (0)