swifttypesmemory-layout

How to get `MemoryLayout` for each member/property of a Type?


Motivation

I'm trying to establish an automatic sanity test algorithm which would raise a warning (via Swift Testing) when an arbitrary Type's MemoryLayout is potentially — it depends on the situation — less than optimal.

For this, I would need a Type's members' MemoryLayout; If MemoryLayout<LessOptimal>.size would return 10 instead of 17, then it could more easily be compared with its stride to raise a warning … but this is not the world we live in.

struct LessOptimal {
    var a: Bool
    var b: UInt
    var c: Bool
}

Non Solutions

Failed attempts

Multiple variations of Mirror/Reflection:

1

Mirror(reflecting: LessOptimal()).children.forEach { child in
   let t = type(of: child.value)
   let layout = MemoryLayout<t>.self
   // … does NOT work!!
}

2

Mirror(reflecting: LessOptimal()).children.forEach { child in
   print(MemoryLayout.size(ofValue: child.value))
   // Size is 32 for all three members!!
}

Solution

  • The second attempt is almost there. child.value is of an existential type - Any. As you have discovered, the size of an existential type is always 32 bytes. You need to open the existential type by passing it to a generic function.

    func sizeOf<T>(_ value: T) -> Int {
        MemoryLayout.size(ofValue: value)
    }
    
    Mirror(reflecting: ...).children.forEach { child in
        print(sizeOf(child.value))
    }
    

    That said, this only works for structs without a CustomReflectable conformance. If the type conform to CustomReflectable, it can give you any Mirror they want. If the type is an enum with associated values, you will only find the size of the tuple containing the associated values for a specific case.