Search code examples
swiftswift-extensionsswift-protocols

Swift why doesn't my generator protocol extension work?


I think my cognition for Swift types/protocols/generics has overflowed. I've been using the pattern of extending "an input stream bytes" by doing something like:

extension GeneratorType where Element == UInt8 {
    func foobar()  {
        ...
    }
}

It's worked in the past for simple stuff. And today I was playing with the following:

protocol Unpackable {
    static func unpack(inout input:IndexingGenerator<[UInt8]>) -> Self
}

extension UInt8:Unpackable {
    static func unpack(inout input:IndexingGenerator<[UInt8]>) -> UInt8 {
        return input.next()!
    }
}

extension UInt16:Unpackable {
    static func unpack(inout input:IndexingGenerator<[UInt8]>) -> UInt16 {
        return UInt16(input.next()!) | (UInt16(input.next()!) << 8)
    }
}

Works fine. But if I try to put the two together with something like

extension GeneratorType where Element == UInt8 {
    func unpackAll() -> (UInt8, UInt16) {
        return (UInt8.unpack(&self), UInt16.unpack(&self))
}

then I get the following error:

Cannot convert value of type 'Self' to expected argument type 'IndexingGenerator<[UInt8]>'

Doesn't an IndexingGenerator conform to GeneratorType? Is its Element not UInt8? Is the error in using IndexingGenerator? I can't specify the argument types as GeneratorType (though I'd really like to be able to).

I'm still waiting for the light bulb to flicker on for Swift types. Some days I really like the language. Other days, I feel like I'm yelling at my dog trying to get him to come, and he just stares at me without moving, then turns and chases down the street anyway.


Solution

  • Try this:

    extension GeneratorType where Element == UInt8 {
        func unpackAll() -> (UInt8, UInt16)? {
            guard let _self = self as? IndexingGenerator<[Element]> else { return nil }
            var vSelf = _self
            return (UInt8.unpack(&vSelf), UInt16.unpack(&vSelf))
        }
    }
    

    Update:

    protocol Unpackable {
        static func unpack<T : GeneratorType where T.Element == UInt8>(inout input:T) -> Self
    }
    
    extension UInt8: Unpackable {
        static func unpack<T : GeneratorType where T.Element == UInt8>(inout input: T) -> UInt8 {
            return input.next()!
        }
    }
    
    extension UInt16: Unpackable {
        static func unpack<T : GeneratorType where T.Element == UInt8>(inout input: T) -> UInt16 {
            return UInt16(input.next()!) | (UInt16(input.next()!) << 8)
        }
    }
    
    extension GeneratorType where Element == UInt8 {
        mutating func unpackAll() -> (UInt8, UInt16) {
            return (UInt8.unpack(&self), UInt16.unpack(&self))
        }
    }