Skip to content

Commit 4fc6b35

Browse files
author
Pouya Yarandi
committed
Add protobuf mirror
1 parent cc3dd41 commit 4fc6b35

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

Sources/SwiftProtobuf/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ add_library(SwiftProtobuf
5858
NameMap.swift
5959
ProtobufAPIVersionCheck.swift
6060
ProtobufMap.swift
61+
ProtobufMirror.swift
6162
ProtoNameProviding.swift
6263
SelectiveVisitor.swift
6364
SimpleExtensionMap.swift
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Sources/SwiftProtobuf/ProtobufMirror.swift - Reflection
2+
//
3+
// Copyright (c) 2014 - 2016 Apple Inc. and the project authors
4+
// Licensed under Apache License v2.0 with Runtime Library Exception
5+
//
6+
// See LICENSE.txt for license information:
7+
// https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
8+
//
9+
// -----------------------------------------------------------------------------
10+
///
11+
/// Enables reflection for protobuf Message.
12+
///
13+
// -----------------------------------------------------------------------------
14+
15+
import Foundation
16+
17+
/// ProtobufMirror is for mirroring a protobuf Message type.
18+
///
19+
/// By using this object, a Message is being mirrored and it enables us to
20+
/// get all its children by their fieldNumber and value. Notice that it is not
21+
/// type safe and it should be used only in cases you need to get values
22+
/// by protobuf model indices.
23+
/// It also provides a field of unknownBytes for fields that could not be
24+
/// decoded by Message protobuf structure.
25+
public struct ProtobufMirror {
26+
27+
public typealias Child = (fieldNumber: Int, value: Any)
28+
29+
private var _children: [Int: Any] = [:]
30+
private var _unknownBytes: [Data] = []
31+
32+
internal mutating func set(_ value: Any, for fieldNumber: Int) {
33+
_children[fieldNumber] = value
34+
}
35+
36+
internal mutating func recordUnknown(_ bytes: Data) {
37+
_unknownBytes.append(bytes)
38+
}
39+
40+
/// Children of a protobuf Message, which refers to all of its fields.
41+
/// The fieldNumber of children is unique across the list.
42+
public var children: [Child] {
43+
_children.map { entry in
44+
(fieldNumber: entry.key, value: entry.value)
45+
}
46+
}
47+
48+
/// A list of bytes that could not be decoded by protobuf Message structure.
49+
public var unknownBytes: [Data] {
50+
_unknownBytes
51+
}
52+
53+
}
54+
55+
struct ReflectionVisitor: Visitor {
56+
57+
private(set) var mirror: ProtobufMirror = .init()
58+
59+
internal init() {}
60+
61+
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
62+
mirror.set(value, for: fieldNumber)
63+
}
64+
65+
mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
66+
mirror.set(value, for: fieldNumber)
67+
}
68+
69+
mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
70+
mirror.set(value, for: fieldNumber)
71+
}
72+
73+
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
74+
mirror.set(value, for: fieldNumber)
75+
}
76+
77+
mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
78+
mirror.set(value, for: fieldNumber)
79+
}
80+
81+
mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
82+
mirror.set(value, for: fieldNumber)
83+
}
84+
85+
mutating func visitSingularEnumField<E>(value: E, fieldNumber: Int) throws {
86+
mirror.set(value, for: fieldNumber)
87+
}
88+
89+
mutating func visitSingularMessageField<M>(value: M, fieldNumber: Int) throws {
90+
mirror.set(value, for: fieldNumber)
91+
}
92+
93+
mutating func visitMapField<KeyType, ValueType>(
94+
fieldType: _ProtobufMap<KeyType, ValueType>.Type,
95+
value: _ProtobufMap<KeyType, ValueType>.BaseType,
96+
fieldNumber: Int
97+
) throws {
98+
mirror.set(value, for: fieldNumber)
99+
}
100+
101+
mutating func visitMapField<KeyType, ValueType>(
102+
fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type,
103+
value: _ProtobufEnumMap<KeyType, ValueType>.BaseType,
104+
fieldNumber: Int
105+
) throws {
106+
mirror.set(value, for: fieldNumber)
107+
}
108+
109+
mutating func visitMapField<KeyType, ValueType>(
110+
fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type,
111+
value: _ProtobufMessageMap<KeyType, ValueType>.BaseType,
112+
fieldNumber: Int
113+
) throws {
114+
mirror.set(value, for: fieldNumber)
115+
}
116+
117+
mutating func visitUnknown(bytes: Data) throws {
118+
mirror.recordUnknown(bytes)
119+
}
120+
121+
}
122+
123+
public extension ProtobufMirror {
124+
125+
/// Throwing init which initiates a ProtobutMirror for reflecting a protobuf
126+
/// Message type.
127+
/// - Parameter message: protobuf Message to be reflected.
128+
init(reflecting message: Message) throws {
129+
var visitor = ReflectionVisitor()
130+
try message.traverse(visitor: &visitor)
131+
self = visitor.mirror
132+
}
133+
134+
}

0 commit comments

Comments
 (0)