2

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.

Travis Griggs
  • 21,522
  • 19
  • 91
  • 167
  • "Doesn't an IndexingGenerator conform to GeneratorType" Yes but not every GeneratorType is an IndexingGenerator. – matt Mar 09 '16 at 00:03
  • I made the arguments `IndexingGenerator<[UInt8]>` only because I couldn't figure out how to do it more generically. I honestly don't care that it's an IndexingGenerator. I would be fine with a Generator of any type, as long as it produced UInt8's. Is there a way to have an argument that is a Protocol of appropriate specification? – Travis Griggs Mar 09 '16 at 16:18
  • Is the trick to declare a *new* protocol that conforms to `GeneratorType` and somehow restrains conforming types to have elements of a `UInt8` ? – Travis Griggs Mar 09 '16 at 16:20
  • Could the solution have something to do with AnyGenerator? – matt Mar 09 '16 at 17:05

1 Answers1

2

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))
    }
}
J.Wang
  • 1,136
  • 6
  • 12
  • Could say `guard var vSelf` and be one line shorter :) – matt Mar 09 '16 at 00:02
  • @matt LOL. Honestly, I never use `var` with `guard` and I assume I can't do it! How stupid I am...Thanks for the tip. – J.Wang Mar 09 '16 at 00:15
  • This forces me to wrap the return type as an optional. Not the end of the world, but not what I was looking for. I'm trying to close the gap between having to use a Protocol to extend a Generic, but having to pass a Generic as the type of an argument. – Travis Griggs Mar 09 '16 at 16:19
  • @TravisGriggs Although I still can not figure out what exactly you want, check out my update see if this makes sense? – J.Wang Mar 11 '16 at 05:25
  • YES! That's what I was looking for I think. Basically, how do I type the argument as the same refined protocol I had extended. So that it didn't fight me when intermixing them. – Travis Griggs Mar 11 '16 at 18:23