Let’s say I have some objects which satisfy a constrained composite pattern: There are leafs (possibly more than one kind) and composites, but each composite may only be composed of components of one kind. Let’s further assume these objects have been tag-length-value encoded and I was to write a custom decoder for them with an API similar to the decoders from the standard library. Here’s how I tried to do it (simplified; the actual decode
implementations are more complex and perform e.g. bounds checking):
import Foundation
protocol Component {
var tag: UInt8 { get }
var length: Int { get }
}
struct Leaf: Component {
var tag: UInt8
var length: Int
var value: [UInt8]
}
struct Composite<T>: Component where T: Component {
var tag: UInt8
var length: Int
var components: [T]
}
protocol TLVDecodable {
init(fromTLV decoder: TLVDecoder) throws
}
extension Leaf: TLVDecodable {
init(fromTLV decoder: TLVDecoder) throws {
self = try decoder.decode(Leaf.self)
}
}
extension Composite: TLVDecodable {
init(fromTLV decoder: TLVDecoder) throws {
self = try decoder.decode(Composite.self)
}
}
class TLVDecoder {
fileprivate let buffer: [UInt8]
fileprivate var cursor = 0
public init(buffer: [UInt8]) {
self.buffer = buffer
}
}
extension TLVDecoder {
func decode(_ type: UInt8.Type) throws -> UInt8 {
let byte = buffer[cursor]
cursor += 1
return byte
}
func decode(_ type: Int.Type) throws -> Int {
let bytes = buffer[cursor...cursor + 4]
cursor += 4
let length = bytes.reduce(0) { soFar, byte in
return soFar << 8 | Int(byte)
}
return length
}
func decode(_ type: Leaf.Type) throws -> Leaf {
let tag = try decode(UInt8.self)
let length = try decode(Int.self)
let value = buffer[cursor...cursor + length]
return Leaf(tag: tag, length: length, value: [UInt8](value))
}
func decode<T: Component>(_ type: Composite<T>.Type) throws -> Composite<T> {
let tag = try decode(UInt8.self)
let length = try decode(Int.self)
var components = [T]()
while cursor < buffer.count {
let t = try decode(T.self) // FIXME: No exact matches in call to instance method 'decode'
components.append(t)
}
return Composite(tag: tag, length: length, components: components)
}
}
However, I’m stuck on the // FIXME:
- why can’t the compiler infer which decode
method to call here?