# Populating/accessing the payload of an enum case at runtime

**URL:** <https://forums.swift.org/t/populating-accessing-the-payload-of-an-enum-case-at-runtime/47921>\
**Category:** Using Swift\
**Tags:** reflection, runtime, enums\
**Created:** [May 5, 2021, 6:22pm UTC](https://forums.swift.org/t/populating-accessing-the-payload-of-an-enum-case-at-runtime/47921 "2021-05-05T18:22:48Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![NSExceptional](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsexceptional/32/6813_2.png) [@NSExceptional](https://forums.swift.org/u/NSExceptional)\
**Post date:** [May 5, 2021, 6:22pm UTC](https://forums.swift.org/t/populating-accessing-the-payload-of-an-enum-case-at-runtime/47921/1 "2021-05-05T18:22:48Z")

</div>

Say I have an enum case as `Any`, and I want to use reflection and unsafe pointers to determine whether this particular case has a payload or not, and access it if it does. I need to be able to determine several things from the runtime:

- How many cases in this enum have payloads at all?
- Is the current case one of the ones with a payload?
- If so, where is that payload?
- How many payloads are in this case, exactly?

Using [Echo](https://github.com/Azoy/Echo), I can easily answer the first question. I am not sure about the rest. Echo seems to be a pretty complete representation of the data available to me at runtime—excluding the functions exposed by the runtime—so I am worried that what I'm asking is not possible at all at runtime. I'm hoping someone here can tell me otherwise.

[TypeLayout.rst](https://github.com/apple/swift/blob/main/docs/ABI/TypeLayout.rst) tells me more about how enums are laid out by the compiler, but not how to fetch that layout for any given enum at runtime, such as for enums with multiple values in a single payload, or enums with more than one payload case.

[Runtime.md](https://github.com/apple/swift/blob/main/docs/Runtime.md) has some interesting funtions related to enum payloads, but I'm not sure any of them will help me.

Edit: it looks like this is something `Mirror` is capable of, as shown below, so it should be possible for me to do! 🙂

 ![Screenshot 2021-05-05 at 1.35.45 PM](https://global.discourse-cdn.com/swift/original/3X/f/2/f251122c96bc395e3b690042cf21ecd03cbf8aab.jpeg)

Also, somehow I overlooked `destructiveProjectEnumData` in Echo's EnumValueWitnessTable.swift, so I guess it's possible he just hasn't finished this area of the library yet

Edit 2: `Mirror` uses `swift_reflectionMirror_subscript` which looks like what I need

---

<div class="post-metadata">

**Author:** ![Alejandro](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alejandro/32/46197_2.png) [@Alejandro](https://forums.swift.org/u/Alejandro)\
**Post date:** [May 5, 2021, 7:23pm UTC](https://forums.swift.org/t/populating-accessing-the-payload-of-an-enum-case-at-runtime/47921/2 "2021-05-05T19:23:31Z")

</div>

Sorry I haven't responded to this question in the repo, but enums are complicated!

As you said, the first question is easy to answer, but answering the rest of them will require some cleverness. There's a fantastic writeup here: [Fixing enums on big-endian systems](https://forums.swift.org/t/fixing-enums-on-big-endian-systems/21730) that I'll use in answering some of these questions.

1. "Is the current case one of the ones with a payload?"

Enum cases are ordered from payload cases to empty cases:

```swift
enum Color {
  case red
  case green
  case blue(Int)
}

// Gets ordered as the following:
enum Color {
  case blue(Int)
  case red
  case green
}

```

Using this, we can answer the second question pretty easily (using code from my library):

```swift
let myFavoriteColor = Color.blue(128)
let colorMetadata = reflectEnum(myFavoriteColor)!

let tag = withUnsafePointer(to: myFavoriteColor) {
  // We need the enum tag, which is the case index.
  return colorMetadata.enumVwt.getEnumTag(for: $0)
}

// This means we have the first case in the enum.
print(tag) // 0

```

Now that we have the tag (case index), determining whether or not this is a payload case is as simple as knowing how many payload cases there are and comparing the tag:

```swift
let isPayloadCase = colorMetadata.descriptor.numPayloadCases > tag

```

1. "If so, where is that payload?"

The link I posted above explains where the payload is.

1. "How many payloads are in this case, exactly?"

We now know that our case is a payload case, getting the payload types is just demangling the mangled name from the field descriptor:

```swift
// Remember that tag = 0 and our first record is
// Color.blue
let record = colorMetadata.descriptor.fields.records[tag]

// I force unwrap here because this is known to be a payload
// case; empty cases do not have a mangled name.

// Swift.Int
print(colorMetadata.type(of: record.mangledTypeName)!)

```

Had our payload case used more than one payload, then the payload type itself would be a tuple of types:

```swift
enum Foo {
  case bar(Int, String, Double)
}

...

// (Swift.Int, Swift.String, Swift.Double)
print(fooMetadata.type(of: bar.mangledTypeName)!)

```

So hopefully that answered all of your questions! I would also like to link [swift/ReflectionMirror.cpp at main · apple/swift · GitHub](https://github.com/apple/swift/blob/main/stdlib/public/runtime/ReflectionMirror.cpp#L560) because it models exactly how one is supposed to copy an enum's payload out to its own value.

---

<div class="post-metadata">

**Author:** ![NSExceptional](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsexceptional/32/6813_2.png) [@NSExceptional](https://forums.swift.org/u/NSExceptional)\
**Post date:** [May 5, 2021, 7:27pm UTC](https://forums.swift.org/t/populating-accessing-the-payload-of-an-enum-case-at-runtime/47921/3 "2021-05-05T19:27:46Z")

</div>

No worries!

Wow, awesome stuff! Thanks! 😄 I suppose `swift_reflectionMirror_subscript` wouldn't be too useful for this since it's read-only?

---

<div class="post-metadata">

**Author:** ![NSExceptional](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsexceptional/32/6813_2.png) [@NSExceptional](https://forums.swift.org/u/NSExceptional)\
**Post date:** [May 5, 2021, 8:10pm UTC](https://forums.swift.org/t/populating-accessing-the-payload-of-an-enum-case-at-runtime/47921/5 "2021-05-05T20:10:01Z")

</div>

@Alejandro Somewhat orthogonal, but do you know how to safely "copy" stuff? Is there a runtime function that will perform the necessary retains for copying an `Any` box?

For example, if I want to copy the payload out of an enum, I was considering writing something like this:

```swift
extension EnumMetadata {
    func getTag(for instance: Any) -> UInt32 {
        var box = container(for: instance)
        return self.enumVwt.getEnumTag(for: box.projectValue())
    }
    
    func copyPayload(from instance: Any) -> (value: Any, type: Any.Type)? {
        let tag = self.getTag(for: instance)
        let isPayloadCase = self.descriptor.numPayloadCases > tag
        if isPayloadCase {
            let caseRecord = self.descriptor.fields.records[Int(tag)]
            let type = self.type(of: caseRecord.mangledTypeName)!
            var caseBox = container(for: instance)
            // Copies in the value and allocates a box as needed
            let payload = AnyExistentialContainer(
                boxing: caseBox.projectValue()~,
                type: reflect(type)
            )
            return (unsafeBitCast(payload, to: Any.self), type)
        }
        
        return nil
    }
}

```

I'm not doing any memory management here. If the enum payload contains an object, or a structure with object references, those need to be retained, right? Unless the compiler would emit a retain after that `unsafeBitCast`, but I don't think it does, does it?

Retaining an object is simple enough, but it gets complicated when the payload is a struct, or another enum case. Do you know if either `swift_assignExistentialWithCopy` or `swift_copyPOD` or something else will do this for me?

Edit: I just realized the `isPOD` flag is probably used to determine when this is necessary, which was going to be my next question

Edit 2: Slava has just pointed me to the functions in the type's VWT. I am going to open a new discussion on Echo about their uses.
