Open
Description
Being able to access this would've allowed me to easily log the name of the payload being processed, as I am using oneof to enumerate all possible IPC payloads. I think this is a more than acceptable use case.
IMO, this data has been sitting in the library for 5 years and counting. It clearly works well enough, even if it is "not quite correct" or a "special-case". If the alternative is reflection, which is not performant, why should this remain an internal API? More importantly, why is the library the only one with easy access to this information?
My workaround uses reflection, building atop of the workaround here:
var nameMapCache: [String: [Int: String]] = [:]
extension _NameMap {
func protoNameFor(rawValue: Int, cacheKey: String) -> String? {
if let cache = nameMapCache[cacheKey] {
return cache[rawValue]
}
let selfMirror = Mirror(reflecting: self)
guard let numberToNameMapChild = selfMirror.children.first(where: { (name, _) -> Bool in
return name == "numberToNameMap"
}), let numberToNameMap = numberToNameMapChild.value as? Dictionary<Int, Any> else {
return nil
}
nameMapCache[cacheKey] = numberToNameMap.compactMapValues { value in
let valueMirror = Mirror(reflecting: value)
guard let protoChild = valueMirror.children.first(where: { (name, _) -> Bool in
return name == "proto"
}), let stringConvertible = protoChild.value as? CustomStringConvertible else {
return nil
}
return stringConvertible.description
}
return protoNameFor(rawValue: rawValue, cacheKey: cacheKey)
}
}
struct PBPayloadCommandNameReader: SwiftProtobuf.Visitor {
let start: Int
mutating func visitSingularDoubleField(value: Double, fieldNumber: Int) throws {
try check(fieldNumber: fieldNumber)
}
mutating func visitSingularInt64Field(value: Int64, fieldNumber: Int) throws {
try check(fieldNumber: fieldNumber)
}
mutating func visitSingularUInt64Field(value: UInt64, fieldNumber: Int) throws {
try check(fieldNumber: fieldNumber)
}
mutating func visitSingularBoolField(value: Bool, fieldNumber: Int) throws {
try check(fieldNumber: fieldNumber)
}
mutating func visitSingularStringField(value: String, fieldNumber: Int) throws {
try check(fieldNumber: fieldNumber)
}
mutating func visitSingularBytesField(value: Data, fieldNumber: Int) throws {
try check(fieldNumber: fieldNumber)
}
mutating func visitSingularEnumField<E>(value: E, fieldNumber: Int) throws where E : Enum {
try check(fieldNumber: fieldNumber)
}
mutating func visitMapField<KeyType, ValueType>(fieldType: _ProtobufMap<KeyType, ValueType>.Type, value: _ProtobufMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws where KeyType : MapKeyType, ValueType : MapValueType {
try check(fieldNumber: fieldNumber)
}
mutating func visitMapField<KeyType, ValueType>(fieldType: _ProtobufEnumMap<KeyType, ValueType>.Type, value: _ProtobufEnumMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws where KeyType : MapKeyType, ValueType : Enum, ValueType.RawValue == Int {
try check(fieldNumber: fieldNumber)
}
mutating func visitMapField<KeyType, ValueType>(fieldType: _ProtobufMessageMap<KeyType, ValueType>.Type, value: _ProtobufMessageMap<KeyType, ValueType>.BaseType, fieldNumber: Int) throws where KeyType : MapKeyType, ValueType : Hashable, ValueType : SwiftProtobuf.Message {
try check(fieldNumber: fieldNumber)
}
mutating func visitUnknown(bytes: Data) throws {
}
enum Found: Error { case found(String?) }
mutating func visitSingularMessageField<M>(value: M, fieldNumber: Int) throws where M : SwiftProtobuf.Message {
try check(fieldNumber: fieldNumber)
}
func check(fieldNumber: Int) throws {
guard fieldNumber >= start else {
return
}
throw Found.found(PBPayload._protobuf_nameMap.protoNameFor(rawValue: fieldNumber, cacheKey: "PBPayloadCommandReflection"))
}
}
/// PBPayload { int64 ID = 1; bool IsResponse = 2; oneof Command { ... }; }
extension PBPayload {
var commandName: String? {
var reader = PBPayloadCommandNameReader(start: 3)
do {
try traverse(visitor: &reader)
} catch {
if case PBPayloadCommandNameReader.Found.found(let name) = error {
return name
}
fatalError("Error while traversing: \(error)")
}
return nil
}
}
Having this functionality provided by the library would be incredibly valuable, and would cut out all of this boilerplate code.
Metadata
Metadata
Assignees
Labels
No labels