-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from christophhagen/1-add-oneof-protobuf-compat…
…ibility Add Oneof Protobuf Compatibility
- Loading branch information
Showing
32 changed files
with
687 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
Sources/BinaryCodable/Decoding/Protobuf/OneOf/OneOfAssociatedValuesDecoder.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import Foundation | ||
|
||
/** | ||
A keyed decoder specifically to decode the associated value within a `ProtobufOneOf` type. | ||
|
||
The decoder receives the data associated with the enum case from `OneOfKeyedDecoder`, | ||
and allows exactly one associated value key (`_0`) to be decoded from the data. | ||
|
||
The decoder allows only one call to `decode(_:forKey:)`, all other access will fail. | ||
*/ | ||
final class OneOfAssociatedValuesDecoder<Key>: AbstractDecodingNode, KeyedDecodingContainerProtocol where Key: CodingKey { | ||
|
||
private let data: Data | ||
|
||
init(data: Data, path: [CodingKey], info: UserInfo) { | ||
self.data = data | ||
super.init(path: path, info: info) | ||
} | ||
|
||
var allKeys: [Key] { | ||
[Key(stringValue: "_0")!] | ||
} | ||
|
||
func contains(_ key: Key) -> Bool { | ||
return true | ||
} | ||
|
||
func decodeNil(forKey key: Key) throws -> Bool { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `decodeNil(forKey:)` while decoding associated value for a `ProtobufOneOf` type") | ||
} | ||
|
||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { | ||
if let _ = type as? DecodablePrimitive.Type { | ||
if let ProtoType = type as? ProtobufDecodable.Type { | ||
if !data.isEmpty { | ||
return try ProtoType.init(fromProtobuf: data) as! T | ||
} else { | ||
return ProtoType.zero as! T | ||
} | ||
} | ||
throw ProtobufDecodingError.unsupported(type: type) | ||
} else if type is AnyDictionary.Type { | ||
let node = ProtoDictDecodingNode(data: data, path: codingPath, info: userInfo) | ||
return try T.init(from: node) | ||
} | ||
let node = ProtoDecodingNode(data: data, path: codingPath, info: userInfo) | ||
return try T.init(from: node) | ||
} | ||
|
||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `nestedContainer(keyedBy:forKey:)` while decoding associated value for a `ProtobufOneOf` type") | ||
} | ||
|
||
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `nestedUnkeyedContainer(forKey:)` while decoding associated value for a `ProtobufOneOf` type") | ||
} | ||
|
||
func superDecoder() throws -> Decoder { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `superDecoder()` while decoding associated value for a `ProtobufOneOf` type") | ||
} | ||
|
||
func superDecoder(forKey key: Key) throws -> Decoder { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `superDecoder(forKey:)` while decoding associated value for a `ProtobufOneOf` type") | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
Sources/BinaryCodable/Decoding/Protobuf/OneOf/OneOfDecodingNode.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import Foundation | ||
|
||
typealias KeyedDataCallback = ((CodingKey) -> Data?) | ||
|
||
/** | ||
A decoding node specifically to decode protobuf `OneOf` structures. | ||
|
||
The node receives all data from the parent container, and hands it to a `OneOfKeyedDecoder`, | ||
which then decodes the keyed values within the enum. | ||
|
||
Attempts to access other containers (`keyed` or `single`) will throw an error. | ||
*/ | ||
final class OneOfDecodingNode: AbstractDecodingNode, Decoder { | ||
|
||
private let content: [DecodingKey: Data] | ||
|
||
init(content: [DecodingKey: Data], path: [CodingKey], info: UserInfo) { | ||
self.content = content | ||
super.init(path: path, info: info) | ||
} | ||
|
||
func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey { | ||
let container = OneOfKeyedDecoder<Key>(content: content, path: codingPath, info: userInfo) | ||
return KeyedDecodingContainer(container) | ||
} | ||
|
||
func unkeyedContainer() throws -> UnkeyedDecodingContainer { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Attempt to access unkeyedContainer() for a type conforming to ProtobufOneOf") | ||
} | ||
|
||
func singleValueContainer() throws -> SingleValueDecodingContainer { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Attempt to access singleValueContainer() for a type conforming to ProtobufOneOf") | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
Sources/BinaryCodable/Decoding/Protobuf/OneOf/OneOfKeyedDecoder.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import Foundation | ||
|
||
/** | ||
A keyed decoder specifically to decode an enum of type `ProtobufOneOf`. | ||
|
||
The decoder only allows a call to `nestedContainer(keyedBy:forKey:)` | ||
to decode the associated value of the `OneOf`, all other access will fail with an error. | ||
|
||
The decoder receives all key-value pairs from the parent node (passed through `OneOfDecodingNode`), | ||
in order to select the appropriate data required to decode the enum (`OneOf` types share the field values with the enclosing message). | ||
*/ | ||
final class OneOfKeyedDecoder<Key>: AbstractDecodingNode, KeyedDecodingContainerProtocol where Key: CodingKey { | ||
|
||
private let content: [DecodingKey: Data] | ||
|
||
init(content: [DecodingKey: Data], path: [CodingKey], info: UserInfo) { | ||
self.content = content | ||
super.init(path: path, info: info) | ||
} | ||
|
||
var allKeys: [Key] { | ||
content.keys.compactMap { key in | ||
switch key { | ||
case .intKey(let value): | ||
return Key(intValue: value) | ||
case .stringKey(let value): | ||
return Key(stringValue: value) | ||
} | ||
} | ||
} | ||
|
||
func contains(_ key: Key) -> Bool { | ||
content.keys.contains { $0.isEqual(to: key) } | ||
} | ||
|
||
func decodeNil(forKey key: Key) throws -> Bool { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `decodeNil(forKey:)` while decoding `ProtobufOneOf` enum") | ||
} | ||
|
||
func decode<T>(_ type: T.Type, forKey key: Key) throws -> T where T : Decodable { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `decode(_,forKey)` while decoding `ProtobufOneOf` enum") | ||
} | ||
|
||
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey { | ||
let data = content.first(where: { $0.key.isEqual(to: key) })?.value ?? Data() | ||
let container = OneOfAssociatedValuesDecoder<NestedKey>(data: data, path: codingPath, info: userInfo) | ||
return KeyedDecodingContainer(container) | ||
} | ||
|
||
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `nestedUnkeyedContainer(forKey:)` while decoding `ProtobufOneOf` enum") | ||
} | ||
|
||
func superDecoder() throws -> Decoder { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `superDecoder()` while decoding `ProtobufOneOf` enum") | ||
} | ||
|
||
func superDecoder(forKey key: Key) throws -> Decoder { | ||
throw ProtobufDecodingError.invalidAccess( | ||
"Unexpected call to `superDecoder(forKey:)` while decoding `ProtobufOneOf` enum") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Oops, something went wrong.