MemoryLayout offset with generics

Hi,

I'm trying to retrieve the offset of items in a struct with an key path (as described in SE-210).
Whenever I try to get the offset for an key path based on a generic type I get nil returned - what is the point I'm missing?
Goal is to use a generic function to provide a CustomPlaygroundDisplayConvertible representation of the memory layout for a bunch of "identical" structures created in Swift / bridged from C with different struct alignment options.

protocol StructureProtocol {
    var u8 : UInt8 { get }
    var u16 : UInt16 { get }
}

struct SampleStruct : StructureProtocol {
    var u8 : UInt8 = 0
    var u16 : UInt16 = 0

    init() { }
}

func offsetWithProtocol<T : StructureProtocol> ( _ clazz: T ) -> Int? {
    return  MemoryLayout<T>.offset(of: \T.u16 )
}

func offsetWithStruct( _ : SampleStruct ) -> Int? { 
    return  MemoryLayout<SampleStruct>.offset(of: \SampleStruct.u16 )
}

let s = SampleStruct()
let o1 = offsetWithProtocol( s ) // returns nil
let o2 = offsetWithStruct( s ) // returns an Int

The generic key path ends up referring to the declaration of the protocol requirement, StructureProtocol.u16, which is not a stored property. This difference between the protocol requirement declaration and the implementation would also be apparent if you tried to compare the \T.u16 and \SampleStruct.u16 key paths for equality, since they would appear to be unequal.

Hmm... Just was under the assumption it worked once I corrected the protocol var definitions to { get set }. But I get still different results even though all types in the code should be identical:

import Foundation

protocol StructureProtocol {
    var u8 : UInt8 { get set }
    var u16 : UInt16 { get set  }
}

struct SampleStruct : StructureProtocol {
    var u8 : UInt8 = 0
    var u16 : UInt16 = 0

    init() { }
}

let s = SampleStruct()

func offsetWithProtocol<T : StructureProtocol> ( _ clazz: T ) -> Int? {
    let keyPath = \T.u16
    print( "\(T.self) \(type(of: keyPath) ) \(MemoryLayout<T>.self)" )
    // => SampleStruct WritableKeyPath<SampleStruct, UInt16> MemoryLayout<SampleStruct>
    return  MemoryLayout<T>.offset(of: keyPath )
}

func offsetWithStruct( _ : SampleStruct ) -> Int? {
    let keypath = \SampleStruct.u16
    print( "\(SampleStruct.self) \(type(of: keypath) ) \(MemoryLayout<SampleStruct>.self)" )
    // => SampleStruct WritableKeyPath<SampleStruct, UInt16> MemoryLayout<SampleStruct>
    return  MemoryLayout<SampleStruct>.offset(of: keypath )
}

let o1 = offsetWithStruct( s ) // returns an Int
let o2 = offsetWithProtocol( s ) // returns nil
Terms of Service

Privacy Policy

Cookie Policy