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
}
Multiple variations of Mirror/Reflection:
Mirror(reflecting: LessOptimal()).children.forEach { child in
let t = type(of: child.value)
let layout = MemoryLayout<t>.self
// … does NOT work!!
}
Mirror(reflecting: LessOptimal()).children.forEach { child in
print(MemoryLayout.size(ofValue: child.value))
// Size is 32 for all three members!!
}
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
.