Hello,

I'm trying to better understand how calls are made between the Swift standard 
library code and the runtime entry points. I've read through most of the 
documentation in the repo but still have some questions.

More specifically, here's an example: the '_EnumMirror' struct below represents 
a mirror reflecting a value whose type is an enum. 

------

struct _EnumMirror : _MirrorType {
  let data: _MagicMirrorData
  var value: Any { return data.value }
  var valueType: Any.Type { return data.valueType }
  // ... more stuff

  var caseName: UnsafePointer<CChar> {
    @_silgen_name("swift_EnumMirror_caseName")get
  }
  // ... (more stuff)
}

------

The 'caseName' property represents the name of the enum value's case (e.g. 
"FirstCase" in Foo.FirstCase) as a C string. This property's getter calls into 
a C++ runtime function named "swift_EnumMirror_caseName", which is reproduced 
below (from Reflection.mm):

extern "C"
const char *swift_EnumMirror_caseName(HeapObject *owner,
                                      const OpaqueValue *value,
                                      const Metadata *type) {
  if (!isEnumReflectable(type))
    return nullptr;

  const auto Enum = static_cast<const EnumMetadata *>(type);
  const auto &Description = Enum->Description->Enum;

  unsigned tag;
  getEnumMirrorInfo(value, type, &tag, nullptr, nullptr);    // effectively, 
same as "tag = type->vw_getEnumTag(value);"
  return getFieldName(Description.CaseNames, tag);
}

Now, I had a few questions about exactly how this interoperation works, because 
I'd like to be able to get the name of an enum case using this entry point from 
a different context (not from within an _EnumMirror property).

* swift_EnumMirror_caseName takes three arguments, but the Swift call site 
doesn't seem to specify what gets passed into the function. Is there a 
convention that is implicitly passing properties on _EnumMirror as arguments 
into the C++ function when it's being called? I did note that there were other 
runtime entry points (like "swift_MagicMirrorData_summary") where the number of 
arguments in the Swift function matched the number of arguments in the C++ 
function, but in those cases the Swift function was a free function and not a 
method.

* What I really want to do is to get the tag of an enum. I wrote a different 
entry point that omits the unused "owner" property and simply calls 
swift_EnumMirror_caseName with nullptr as the first argument. This other C++ 
function takes 'value' (an OpaqueValue*) and 'type' (a Metadata*). I've 
surmised that 'type' should be the Swift metatype of the enum instance (e.g. 
myEnum.dynamicType), and I do get the case names table. However, if I pass in 
the enum instance itself as 'value', my tag is always retrieved as 0. I noticed 
that there's some sort of indirection in the form of "vw_getEnumTag", which 
goes through something called the "value witness". Is there somewhere I can 
read up about the value witness concept? I assume the reason the 'original' 
code worked was because it was passing in a different object as 'value', maybe 
one that could serve as a value witness for the reflected-upon instance's type.

Thanks a lot for your time.

Best,
Austin

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to