Skip to content

Commit 667fdbc

Browse files
authored
Add ProtobufMessage support (#137)
* Update ProtobufMessage * Update ProtobufEncoder and ProtobufDecoder * Fix warning issue
1 parent 0a00b95 commit 667fdbc

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// ProtobufDecoder.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for RELEASE_2024
6+
// Status: WIP
7+
8+
import Foundation
9+
10+
package struct ProtobufDecoder {
11+
package enum DecodingError: Error {
12+
case failed
13+
}
14+
15+
package typealias Field = ProtobufFormat.Field
16+
package typealias WireType = ProtobufFormat.WireType
17+
18+
19+
var data: NSData
20+
var ptr: UnsafeRawPointer
21+
var end: UnsafeRawPointer
22+
var packedField: Field = Field(rawValue: 0)
23+
var packedEnd: UnsafeRawPointer
24+
var stack: [UnsafeRawPointer] = []
25+
package var userInfo: [CodingUserInfoKey : Any] = [:]
26+
27+
package init(_ data: Data) {
28+
let nsData = data as NSData
29+
self.data = nsData
30+
let ptr = nsData.bytes
31+
self.ptr = ptr
32+
self.end = ptr + nsData.length
33+
self.packedEnd = ptr
34+
}
35+
}
36+
37+
extension ProtobufDecoder {
38+
// TODO: Implement decoding methods
39+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// ProtobufEncoder.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for RELEASE_2024
6+
// Status: WIP
7+
// ID: C7B3AAD101AF9EA76FC322BD6EF713E6
8+
9+
import Foundation
10+
11+
package struct ProtobufEncoder {
12+
package enum EncodingError: Error {
13+
case failed
14+
}
15+
package typealias Field = ProtobufFormat.Field
16+
package typealias WireType = ProtobufFormat.WireType
17+
18+
var buffer: UnsafeMutableRawPointer = .init(bitPattern: 0)!
19+
var size: Int = 0
20+
var capacity: Int = 0
21+
var stack: [Int] = []
22+
package var userInfo: [CodingUserInfoKey: Any] = [:]
23+
24+
package static func encoding(_ body: (inout ProtobufEncoder) throws -> Void) rethrows -> Data {
25+
var encoder = ProtobufEncoder()
26+
try body(&encoder)
27+
defer { free(encoder.buffer) }
28+
return encoder.takeData()
29+
}
30+
31+
package static func encoding<T>(_ value: T) throws -> Data where T: ProtobufEncodableMessage {
32+
try encoding { encoder in
33+
try value.encode(to: &encoder)
34+
}
35+
}
36+
37+
private func takeData() -> Data {
38+
Data(bytes: buffer, count: size)
39+
}
40+
}
41+
42+
extension ProtobufEncoder {
43+
// TODO: Implement encoding methods
44+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//
2+
// ProtobufMessage.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for RELEASE_2024
6+
// Status: Complete
7+
8+
import Foundation
9+
10+
// MARK: - ProtobufMessage
11+
12+
package protocol ProtobufEncodableMessage {
13+
func encode(to encoder: inout ProtobufEncoder) throws
14+
}
15+
package protocol ProtobufDecodableMessage {
16+
init(from decoder: inout ProtobufDecoder) throws
17+
}
18+
19+
package typealias ProtobufMessage = ProtobufDecodableMessage & ProtobufEncodableMessage
20+
21+
// MARK: - ProtobufEnum
22+
23+
package protocol ProtobufEnum {
24+
var protobufValue: UInt { get }
25+
init?(protobufValue: UInt)
26+
}
27+
28+
extension ProtobufEnum where Self: RawRepresentable, RawValue: BinaryInteger {
29+
package var protobufValue: UInt {
30+
UInt(rawValue)
31+
}
32+
33+
package init?(protobufValue: UInt) {
34+
self.init(rawValue: RawValue(protobufValue))
35+
}
36+
}
37+
38+
// MARK: - ProtobufTag
39+
40+
package protocol ProtobufTag: Equatable {
41+
var rawValue: UInt { get }
42+
init(rawValue: UInt)
43+
}
44+
45+
// MARK: - ProtobufFormat
46+
47+
package enum ProtobufFormat {
48+
package struct WireType: Equatable {
49+
package let rawValue: UInt
50+
package init(rawValue: UInt) {
51+
self.rawValue = rawValue
52+
}
53+
54+
package static var varint: ProtobufFormat.WireType { WireType(rawValue: 0) }
55+
package static var fixed64: ProtobufFormat.WireType { WireType(rawValue: 1) }
56+
package static var lengthDelimited: ProtobufFormat.WireType { WireType(rawValue: 2) }
57+
package static var fixed32: ProtobufFormat.WireType { WireType(rawValue: 5) }
58+
}
59+
60+
package struct Field: Equatable {
61+
package var rawValue: UInt
62+
package init(rawValue: UInt) {
63+
self.rawValue = rawValue
64+
}
65+
66+
// field = (field_number << 3) | wire_type
67+
// See https://protobuf.dev/programming-guides/encoding/
68+
package init(_ tag: UInt, wireType: WireType) {
69+
rawValue = (tag << 3) | wireType.rawValue
70+
}
71+
72+
package var tag: UInt {
73+
rawValue >> 3
74+
}
75+
76+
package var wireType: WireType {
77+
WireType(rawValue: rawValue & 7)
78+
}
79+
80+
@inline(__always)
81+
package func tag<T>(as: T.Type = T.self) -> T where T: ProtobufTag {
82+
T(rawValue: tag)
83+
}
84+
}
85+
}
86+
87+
// MARK: - CoddleByProtobuf
88+
89+
package protocol CodaleByProtobuf: Codable, ProtobufMessage {}
90+
91+
extension CodaleByProtobuf {
92+
func encode(to encoder: any Encoder) throws {
93+
let data = try ProtobufEncoder.encoding { protobufEncoder in
94+
protobufEncoder.userInfo = encoder.userInfo
95+
try encode(to: &protobufEncoder)
96+
}
97+
var container = encoder.singleValueContainer()
98+
try container.encode(data)
99+
}
100+
101+
init(from decoder: any Decoder) throws {
102+
let container = try decoder.singleValueContainer()
103+
let data = try container.decode(Data.self)
104+
var protobufDecoder = ProtobufDecoder(data)
105+
protobufDecoder.userInfo = decoder.userInfo
106+
self = try Self(from: &protobufDecoder)
107+
}
108+
}
109+
110+
// MARK: - ProtobufCodable
111+
112+
@propertyWrapper
113+
package struct ProtobufCodable<Value>: Swift.Codable where Value: ProtobufMessage {
114+
package var wrappedValue: Value
115+
package init(wrappedValue: Value) {
116+
self.wrappedValue = wrappedValue
117+
}
118+
119+
package func encode(to encoder: any Encoder) throws {
120+
let data = try ProtobufEncoder.encoding { protobufEncoder in
121+
protobufEncoder.userInfo = encoder.userInfo
122+
try wrappedValue.encode(to: &protobufEncoder)
123+
}
124+
var container = encoder.singleValueContainer()
125+
try container.encode(data)
126+
}
127+
128+
package init(from decoder: any Decoder) throws {
129+
let container = try decoder.singleValueContainer()
130+
let data = try container.decode(Data.self)
131+
var protobufDecoder = ProtobufDecoder(data)
132+
protobufDecoder.userInfo = decoder.userInfo
133+
wrappedValue = try Value(from: &protobufDecoder)
134+
}
135+
}
136+
137+
extension ProtobufCodable: Equatable where Value: Equatable {
138+
package static func == (lhs: ProtobufCodable<Value>, rhs: ProtobufCodable<Value>) -> Bool {
139+
lhs.wrappedValue == rhs.wrappedValue
140+
}
141+
}

0 commit comments

Comments
 (0)