Swift进阶-Mirror解析

作者: 顶级蜗牛 | 来源:发表于2022-02-28 09:23 被阅读0次

    Swift进阶-类与结构体
    Swift-函数派发
    Swift进阶-属性
    Swift进阶-指针
    Swift进阶-内存管理
    Swift进阶-TargetClassMetadata和TargetStructMetadata数据结构源码分析
    Swift进阶-Mirror解析
    Swift进阶-闭包
    Swift进阶-协议
    Swift进阶-泛型
    Swift进阶-String源码解析
    Swift进阶-Array源码解析

    课前知识储备
    • AnyObject代表 - 任意类的实例、类的类型、仅类遵守的协议
    class Teacher {
        var age = 18
    }
    
    var t = Teacher()
    var t1: AnyObject = t // 类的实例对象
    var t2: AnyObject = Teacher.self // 类的类型
    
    // 协议只允许被类遵守
    protocol MyProtocol: AnyObject {
    }
    
    extension Teacher: MyProtocol {
    }
    
    • Any:代表任意类型,包含function类型或者optional类型。
    let array: [AnyObject] = [1, "aaa"] // 报错!Int是基本数据类型
    let array: [Any] = [1, "aaa"] // 修改后写法
    
    • AnyClass: 代表任意实例对象的类型
    class Teacher {
        var age = 18
    }
    
    var t: AnyClass = Teacher.self // 它属于Teacher.Type
    
    • type(of: T): 获取动态类型
    let age = 10
    // value静态类型是Any
    func test(_ value: Any) {
        print(type(of: value))
    }
    test(age) // Int
    
    • T.self:如果T是实例对象,那T.self返回的是实例自己;如果T是类型,那T.self返回的是元类型。
    class Teacher {
        var age = 18
    }
    
    var t = Teacher()
    
    var t1 = t.self      // 返回的是 t
    var t2 = t.self.self // 返回的是 t
    var t3 = Teacher.self // 返回的是 Teacher的元类型
    
    • selfSelf

    self的使用场景

    class Teacher {
        var age = 18
        
        func test() {
            print(self) // self是当前实例对象
        }
        
        static func test1() {
            print(self) // Teacher类对象
        }
    }
    

    Self的使用场景
    1.作为方法的返回类型,Self指代返回当前类的对象
    2.在协议中方法返回类型 ,Self指代返回遵循这个协议的类型的对象
    3.可用于使用静态属性

    class Teacher {
        static let age = 18
    
        func test() -> Self {
            return self  // 返回当前实例对象
        }
    }
    
    class Person {
        static let age = 18
        let age1 = age
        var age2 = age
        
        lazy var age3 = Self.age
    }
    
    protocol MyProtocol {
        func get() -> Self
    }
    

    一、Mirror的基本用法

    反射就是可以动态获取 类型、成员信息,在运行时可调用方法、属性 等行为的特性。
    基于原生Swift使用Runtime的诸多局限性,它的标准库提供了反射机制来让我们访问成员信息。

    Swift的反射机制是基于一个叫Mirror的结构体来实现的。

    class Teacher {
        var age = 18
        
        func teach() {
            print("teach")
        }
    }
    
    let  t = Teacher()
    let mirror = Mirror(reflecting: t)
    for property in mirror.children {
        print("\(property.label!): \(property.value)")
    }
    
    // age: 18
    

    ps: 没有办法访问到当前的函数teach,如果想要访问函数,需要把函数定义成属性信息。
    那我们可以简单地封装一下,得到一个对象的key-value:

    // 调用函数直接得到一个对象的key-value
    func getKeyValue(_ mirrorObj: Any) -> [String: Any] {
        let mirror = Mirror(reflecting: mirrorObj)
        guard !mirror.children.isEmpty else{ return mirrorObj }
        var result: [String: Any] = [:]
        for child in mirror.children{
            if let key = child.label{
                result[key] = test(child.value)
            }else{
                print("No Keys")
            }
        }
        return result
    }
    

    然而我们还可以定义出更高级Mirror的封装

    class Teacher {
        var age: Int
        var name: String
        init(age: Int, name: String) {
            self.age = age
            self.name = name
        }
    }
    
    enum JSONMapError: Error{
        case emptyKey
        case notConformProtocol
    }
    
    protocol JSONMap{
      func jsonMap() throws -> Any
    }
    
    //rethrows
    extension JSONMap{
      func jsonMap() throws -> Any{
        let mirror = Mirror(reflecting: self)
    
        guard !mirror.children.isEmpty else{ return self }
    
        var result: [String: Any] = [:]
    
        for child in mirror.children{
           if let value = child.value as? JSONMap{
             if let key = child.label{
                result[key] = try? value.jsonMap()
              }else{
                return JSONMapError.emptyKey
              }
           }else{
               return JSONMapError.notConformProtocol
           }
        }
    
        return result
      }
    }
    
    extension Teacher: JSONMap{}
    extension Int: JSONMap{}
    extension String: JSONMap{}
    
    // 使用:
    var t = Teacher(age: 18, name: "安老师")
    do {
       try t.jsonMap()
    } catch {
        print(error)
    }
    

    二、Mirror源码解析

    打开Swift源码搜索到Mirror.swift,很快清晰地发现Mirror是一个结构体,快速定位到初始化函数:

      public init(reflecting subject: Any) {
        if case let customized as CustomReflectable = subject {
          self = customized.customMirror
        } else {
          self = Mirror(internalReflecting: subject)
        }
      }
    

    首先看到初始化函数接收一个 Any 参数 subject。要么subject是遵循 CustomReflectable 协议,如果是则调用 customized.customMirror得到Mirror对象,要么去创建Mirror。

    我们来看一下CustomReflectable 协议具体用法:

    class Teacher: CustomReflectable {
        var age: Int
        var name: String
        init(age: Int, name: String) {
            self.age = age
            self.name = name
        }
    
        var customMirror: Mirror{
            let info = KeyValuePairs<String, Any>.init(dictionaryLiteral: ("age", age),("name", name))
            let mirror = Mirror.init(self, children: info, displayStyle: .class, ancestorRepresentation: .generated)
            return mirror
        }
    }
    

    当实现这个 CustomReflectable 最直观的区别在与我们在 lldb debug 中会出现更详细的 debug 信息:

    CustomReflectable

    没有实现这个协议的时候就会只打印地址。
    了解完CustomReflectable就需要往下了解Mirror的初始化方法 Mirror(internalReflecting: subject),全局搜索一下Mirror(internalReflecting:找到在 ReflectionMirror.swift

    Mirror(internalReflecting:)

    找到_getNormalizedType在哪里声明的

    _getNormalizedType声明

    编译器字段@_silgen_name是swift的一个隐藏符号,作用是将某个c/c++函数直接映射为swift函数。

    番外知识举例 @_silgen_name 的使用:
    1.新建一个 C file 文件,取名为TestC
    2.在TestC.c写一个C函数实现

    #include "TestC.h"
    int c_add(int a, int b) {
        return a + b;
    }
    

    3.在.swift 文件声明一个映射函数

    @_silgen_name("c_add")
    func swift_add(a: Int32, b: Int32) -> Int32
    

    4.直接调用 swift_add

    var value = swift_add(a: 10, b: 20)
    print(value)
    

    再回到 Mirror初始化源码里边,在获取subject的真实类型信息的时候,调用了_getNormalizedType,而源码里这个函数的声明看出,实际上这个函数是在调用 swift_reflectionMirror_normalizedType 函数.

    找到ReflectionMirror.cpp里边的函数名为swift_reflectionMirror_normalizedType

    // func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
    SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
    const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
                                                          const Metadata *type,
                                                          const Metadata *T) {
      return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
    }
    

    它调用了一个 call函数(它返回了一个闭包),当前呢调用了call函数返回了类型信息。

    template<typename F>
    auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
              const F &f) -> decltype(f(nullptr))
    {
      const Metadata *type;
      OpaqueValue *value;
      std::tie(type, value) = unwrapExistential(T, passedValue);
      
      if (passedType != nullptr) {
        type = passedType;
      }
      
      auto call = [&](ReflectionMirrorImpl *impl) {
        impl->type = type;
        impl->value = value;
        auto result = f(impl);
        return result;
      };
      
      auto callClass = [&] {
        if (passedType == nullptr) {
          // Get the runtime type of the object.
          const void *obj = *reinterpret_cast<const void * const *>(value);
          auto isa = _swift_getClass(obj);
    
          // Look through artificial subclasses.
          while (isa->isTypeMetadata() && isa->isArtificialSubclass()) {
            isa = isa->Superclass;
          }
          passedType = isa;
        }
    
      #if SWIFT_OBJC_INTEROP
        // If this is a pure ObjC class, reflect it using ObjC's runtime facilities.
        // ForeignClass (e.g. CF classes) manifests as a NULL class object.
        auto *classObject = passedType->getClassObject();
        if (classObject == nullptr || !classObject->isTypeMetadata()) {
          ObjCClassImpl impl;
          return call(&impl);
        }
      #endif
    
        // Otherwise, use the native Swift facilities.
        ClassImpl impl;
        return call(&impl);
      };
      
      switch (type->getKind()) {
        case MetadataKind::Tuple: {
          TupleImpl impl;
          return call(&impl);
        }
    
        case MetadataKind::Struct: {
          StructImpl impl;
          return call(&impl);
        }
        
    
        case MetadataKind::Enum:
        case MetadataKind::Optional: {
          EnumImpl impl;
          return call(&impl);
        }
          
        case MetadataKind::ObjCClassWrapper:
        case MetadataKind::ForeignClass:
        case MetadataKind::Class: {
          return callClass();
        }
    
        case MetadataKind::Metatype:
        case MetadataKind::ExistentialMetatype: {
          MetatypeImpl impl;
          return call(&impl);
        }
    
        case MetadataKind::Opaque: {
    #if SWIFT_OBJC_INTEROP
          // If this is the AnyObject type, use the dynamic type of the
          // object reference.
          if (type == &METADATA_SYM(BO).base) {
            return callClass();
          }
    #endif
          // If this is the Builtin.NativeObject type, and the heap object is a
          // class instance, use the dynamic type of the object reference.
          if (type == &METADATA_SYM(Bo).base) {
            const HeapObject *obj
              = *reinterpret_cast<const HeapObject * const*>(value);
            if (obj->metadata->getKind() == MetadataKind::Class) {
              return callClass();
            }
          }
          SWIFT_FALLTHROUGH;
        }
    
        /// TODO: Implement specialized mirror witnesses for all kinds.
        default:
          break;
    
        // Types can't have these kinds.
        case MetadataKind::HeapLocalVariable:
        case MetadataKind::HeapGenericLocalVariable:
        case MetadataKind::ErrorObject:
          swift::crash("Swift mirror lookup failure");
        }
    
        // If we have an unknown kind of type, or a type without special handling,
        // treat it as opaque.
        OpaqueImpl impl;
        return call(&impl);
    }
    
    } // end anonymous namespace
    

    可以看到call函数体里面return之前使用switch做了一系列的类型判断,来确定返回是call回调还是callClass回调

    call回调

    而最终所有的结果信息(type、value) 都是由当前的 ReflectionMirrorImpl 这个结构体去实现的。
    看看switch里面怎么做判断的:

    switch (type->getKind()) {
        case MetadataKind::Tuple: {
          TupleImpl impl;
          return call(&impl);
        }
    
        case MetadataKind::Struct: {
          StructImpl impl;
          return call(&impl);
        }
        
    
        case MetadataKind::Enum:
        case MetadataKind::Optional: {
          EnumImpl impl;
          return call(&impl);
        }
          
        case MetadataKind::ObjCClassWrapper:
        case MetadataKind::ForeignClass:
        case MetadataKind::Class: {
          return callClass();
        }
    
        case MetadataKind::Metatype:
        case MetadataKind::ExistentialMetatype: {
          MetatypeImpl impl;
          return call(&impl);
        }
    
        case MetadataKind::Opaque: {
    #if SWIFT_OBJC_INTEROP
          // If this is the AnyObject type, use the dynamic type of the
          // object reference.
          if (type == &METADATA_SYM(BO).base) {
            return callClass();
          }
    #endif
          // If this is the Builtin.NativeObject type, and the heap object is a
          // class instance, use the dynamic type of the object reference.
          if (type == &METADATA_SYM(Bo).base) {
            const HeapObject *obj
              = *reinterpret_cast<const HeapObject * const*>(value);
            if (obj->metadata->getKind() == MetadataKind::Class) {
              return callClass();
            }
          }
          SWIFT_FALLTHROUGH;
        }
    
        /// TODO: Implement specialized mirror witnesses for all kinds.
        default:
          break;
    
        // Types can't have these kinds.
        case MetadataKind::HeapLocalVariable:
        case MetadataKind::HeapGenericLocalVariable:
        case MetadataKind::ErrorObject:
          swift::crash("Swift mirror lookup failure");
        }
    
        // If we have an unknown kind of type, or a type without special handling,
        // treat it as opaque.
        OpaqueImpl impl;
        return call(&impl);
    }
    

    判断类型如果是 Tuple 则返回TupleImpl,如果是Struct 则返回StructImpl 等...
    那如果想反射不同类型的信息,就要把要反射的类型去继承这个ReflectionMirrorImpl抽象结构体,提供具体的类型信息。

    ReflectionMirrorImpl是反射实现的抽象基类:

    // Abstract base class for reflection implementations.
    struct ReflectionMirrorImpl {
      const Metadata *type;
      OpaqueValue *value;
      
      virtual char displayStyle() = 0;
      virtual intptr_t count() = 0;
      virtual intptr_t childOffset(intptr_t index) = 0;
      virtual const FieldType childMetadata(intptr_t index,
                                            const char **outName,
                                            void (**outFreeFunc)(const char *)) = 0;
      virtual AnyReturn subscript(intptr_t index, const char **outName,
                                  void (**outFreeFunc)(const char *)) = 0;
      virtual const char *enumCaseName() { return nullptr; }
    
    #if SWIFT_OBJC_INTEROP
      virtual id quickLookObject() { return nil; }
    #endif
      
      // For class types, traverse through superclasses when providing field
      // information. The base implementations call through to their local-only
      // counterparts.
      virtual intptr_t recursiveCount() {
        return count();
      }
      virtual intptr_t recursiveChildOffset(intptr_t index) {
        return childOffset(index);
      }
      virtual const FieldType recursiveChildMetadata(intptr_t index,
                                                     const char **outName,
                                                     void (**outFreeFunc)(const char *))
      {
        return childMetadata(index, outName, outFreeFunc);
      }
    
      virtual ~ReflectionMirrorImpl() {}
    };
    

    EnumImpl的源码声明:

    // Implementation for enums.
    struct EnumImpl : ReflectionMirrorImpl {
      //是否能反射
      bool isReflectable() {
        //做一个metadata的强转
        const auto *Enum = static_cast<const EnumMetadata *>(type);
        //找到metadata的Description
        const auto &Description = Enum->getDescription();
        //根据Description中的isReflectable字段来判断是否可以反射
        return Description->isReflectable();
      }
      
      const char *getInfo(unsigned *tagPtr = nullptr,
                          const Metadata **payloadTypePtr = nullptr,
                          bool *indirectPtr = nullptr) {
        // 'tag' is in the range [0..NumElements-1].
        unsigned tag = type->vw_getEnumTag(value);
    
        StringRef name;
        FieldType info;
        //获取FieldDescriptor的信息,也就是属性信息存放的地方
        std::tie(name, info) = getFieldAt(type, tag);
        const Metadata *payloadType = info.getType();
        bool indirect = info.isIndirect();
    
        if (tagPtr)
          *tagPtr = tag;
        if (payloadTypePtr)
          *payloadTypePtr = payloadType;
        if (indirectPtr)
          *indirectPtr = indirect;
        
        return name.data();
      }
    
      char displayStyle() override {
        return 'e';
      }
      
      //获取count
      intptr_t count() override {
        if (!isReflectable()) {
          return 0;
        }
        
        // No fields if reflecting the enumeration type instead of a case
        if (!value) {
          return 0;
        }
    
        const Metadata *payloadType;
        //获取挂载类型,也就是Metadata
        getInfo(nullptr, &payloadType, nullptr);
        return (payloadType != nullptr) ? 1 : 0;
      }
    
      ...
    }
    

    获取FieldDescriptor的信息是怎么获取的呢?
    看看getFieldAt的源码:

    static std::pair<StringRef /*name*/, FieldType /*fieldInfo*/>
    getFieldAt(const Metadata *base, unsigned index) {
      using namespace reflection;
      
      // If we failed to find the field descriptor metadata for the type, fall
      // back to returning an empty tuple as a standin.
      auto failedToFindMetadata = [&]() -> std::pair<StringRef, FieldType> {
        auto typeName = swift_getTypeName(base, /*qualified*/ true);
        missing_reflection_metadata_warning(
          "warning: the Swift runtime found no field metadata for "
          "type '%*s' that claims to be reflectable. Its fields will show up as "
          "'unknown' in Mirrors\n",
          (int)typeName.length, typeName.data);
        return {"unknown", FieldType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))};
      };
      //获取TargetxxxDescriptor信息
      auto *baseDesc = base->getTypeContextDescriptor();
      if (!baseDesc)
        return failedToFindMetadata();
    
      //获取descriptor里的FieldDescriptor的信息
      auto *fields = baseDesc->Fields.get();
      if (!fields)
        return failedToFindMetadata();
      
      auto &field = fields->getFields()[index];
      // Bounds are always valid as the offset is constant.
      //获取属性的名称
      auto name = field.getFieldName();
      ...
    }
    
    • 此时的源码可以分析出上一篇文章Swift进阶-属性通过Mach-O找到我们的属性名称是一致的。

    Mirror的工作原理:可以看出Mirro是通过Metadata(当前类型的元数据)、getDescription(当前类型的描述)、FieldDescription(当前类型属性的描述)来实现的。

    三、enum数据结构还原

    来看源码全局搜索在Metadata.h找到 TargetEnumMetadata的源码:

    /// The structure of type metadata for enums.
    template <typename Runtime>
    struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
      using StoredPointer = typename Runtime::StoredPointer;
      using StoredSize = typename Runtime::StoredSize;
      using TargetValueMetadata<Runtime>::TargetValueMetadata;
    
      const TargetEnumDescriptor<Runtime> *getDescription() const {
        return llvm::cast<TargetEnumDescriptor<Runtime>>(this->Description);
      }
    
      // The first trailing field of enum metadata is always the generic
      // argument array.
    
      /// True if the metadata records the size of the payload area.
      bool hasPayloadSize() const {
        return getDescription()->hasPayloadSizeOffset();
      }
    
      /// Retrieve the size of the payload area.
      ///
      /// `hasPayloadSize` must be true for this to be valid.
      StoredSize getPayloadSize() const {
        assert(hasPayloadSize());
        auto offset = getDescription()->getPayloadSizeOffset();
        const StoredSize *asWords = reinterpret_cast<const StoredSize *>(this);
        asWords += offset;
        return *asWords;
      }
    
      StoredSize &getPayloadSize() {
        assert(hasPayloadSize());
        auto offset = getDescription()->getPayloadSizeOffset();
        StoredSize *asWords = reinterpret_cast<StoredSize *>(this);
        asWords += offset;
        return *asWords;
      }
    
      bool isStaticallySpecializedGenericMetadata() const {
        auto *description = getDescription();
        if (!description->isGeneric())
          return false;
    
        auto *trailingFlags = getTrailingFlags();
        if (trailingFlags == nullptr)
          return false;
    
        return trailingFlags->isStaticSpecialization();
      }
    
      bool isCanonicalStaticallySpecializedGenericMetadata() const {
        auto *description = getDescription();
        if (!description->isGeneric())
          return false;
    
        auto *trailingFlags = getTrailingFlags();
        if (trailingFlags == nullptr)
          return false;
    
        return trailingFlags->isCanonicalStaticSpecialization();
      }
    
      const MetadataTrailingFlags *getTrailingFlags() const {
        auto description = getDescription();
        auto flags = description->getFullGenericContextHeader()
                         .DefaultInstantiationPattern->PatternFlags;
        if (!flags.hasTrailingFlags())
          return nullptr;
        auto offset =
            getGenericArgumentOffset() +
            description->getFullGenericContextHeader().Base.getNumArguments() +
            (hasPayloadSize() ? 1 : 0);
        auto asWords = reinterpret_cast<const void *const *>(this);
        return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
      }
    
      static constexpr int32_t getGenericArgumentOffset() {
        return sizeof(TargetEnumMetadata<Runtime>) / sizeof(StoredPointer);
      }
    
      static bool classof(const TargetMetadata<Runtime> *metadata) {
        return metadata->getKind() == MetadataKind::Enum
          || metadata->getKind() == MetadataKind::Optional;
      }
    };
    using EnumMetadata = TargetEnumMetadata<InProcess>;
    

    继承自TargetValueMetadata

    /// The common structure of metadata for structs and enums.
    template <typename Runtime>
    struct TargetValueMetadata : public TargetMetadata<Runtime> {
      using StoredPointer = typename Runtime::StoredPointer;
      TargetValueMetadata(MetadataKind Kind,
                          const TargetTypeContextDescriptor<Runtime> *description)
          : TargetMetadata<Runtime>(Kind), Description(description) {}
    
      /// An out-of-line description of the type.
      TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
    
      static bool classof(const TargetMetadata<Runtime> *metadata) {
        return metadata->getKind() == MetadataKind::Struct
          || metadata->getKind() == MetadataKind::Enum
          || metadata->getKind() == MetadataKind::Optional;
      }
    
      ConstTargetMetadataPointer<Runtime, TargetValueTypeDescriptor>
      getDescription() const {
        return Description;
      }
    
      typename Runtime::StoredSignedPointer
      getDescriptionAsSignedPointer() const {
        return Description;
      }
    };
    using ValueMetadata = TargetValueMetadata<InProcess>;
    

    继承自TargetMetadata:

    template <typename Runtime>
    struct TargetMetadata {
      using StoredPointer = typename Runtime::StoredPointer;
    
      /// The basic header type.
      typedef TargetTypeMetadataHeader<Runtime> HeaderType;
    
      constexpr TargetMetadata()
        : Kind(static_cast<StoredPointer>(MetadataKind::Class)) {}
      constexpr TargetMetadata(MetadataKind Kind)
        : Kind(static_cast<StoredPointer>(Kind)) {}
    
    #if SWIFT_OBJC_INTEROP
    protected:
      constexpr TargetMetadata(TargetAnyClassMetadataObjCInterop<Runtime> *isa)
        : Kind(reinterpret_cast<StoredPointer>(isa)) {}
    #endif
    
    private:
      /// The kind. Only valid for non-class metadata; getKind() must be used to get
      /// the kind value.
      StoredPointer Kind;
    public:
      /// Get the metadata kind.
      MetadataKind getKind() const {
        return getEnumeratedMetadataKind(Kind);
      }
      
      /// Set the metadata kind.
      void setKind(MetadataKind kind) {
        Kind = static_cast<StoredPointer>(kind);
      }
    
    protected:
      const TargetAnyClassMetadata<Runtime> *getClassISA() const {
        return reinterpret_cast<const TargetAnyClassMetadata<Runtime> *>(Kind);
      }
      void setClassISA(const TargetAnyClassMetadata<Runtime> *isa) {
        Kind = reinterpret_cast<StoredPointer>(isa);
      }
    
    public:
      /// Is this a class object--the metadata record for a Swift class (which also
      /// serves as the class object), or the class object for an ObjC class (which
      /// is not metadata)?
      bool isClassObject() const {
        return static_cast<MetadataKind>(getKind()) == MetadataKind::Class;
      }
      
      /// Does the given metadata kind represent metadata for some kind of class?
      static bool isAnyKindOfClass(MetadataKind k) {
        switch (k) {
        case MetadataKind::Class:
        case MetadataKind::ObjCClassWrapper:
        case MetadataKind::ForeignClass:
          return true;
    
        default:
          return false;
        }
      }
      
      /// Is this metadata for an existential type?
      bool isAnyExistentialType() const {
        switch (getKind()) {
        case MetadataKind::ExistentialMetatype:
        case MetadataKind::Existential:
          return true;
    
        default:
          return false;
        }
      }
      
      /// Is this either type metadata or a class object for any kind of class?
      bool isAnyClass() const {
        return isAnyKindOfClass(getKind());
      }
    
      const ValueWitnessTable *getValueWitnesses() const {
        return asFullMetadata(this)->ValueWitnesses;
      }
    
      const TypeLayout *getTypeLayout() const {
        return getValueWitnesses()->getTypeLayout();
      }
    
      void setValueWitnesses(const ValueWitnessTable *table) {
        asFullMetadata(this)->ValueWitnesses = table;
      }
      
      // Define forwarders for value witnesses. These invoke this metadata's value
      // witness table with itself as the 'self' parameter.
      #define WANT_ONLY_REQUIRED_VALUE_WITNESSES
      #define FUNCTION_VALUE_WITNESS(WITNESS, UPPER, RET_TYPE, PARAM_TYPES)    \
        template<typename...A>                                                 \
        _ResultOf<ValueWitnessTypes::WITNESS ## Unsigned>::type                            \
        vw_##WITNESS(A &&...args) const {                                      \
          return getValueWitnesses()->WITNESS(std::forward<A>(args)..., this); \
        }
      #define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE)
      #include "swift/ABI/ValueWitness.def"
    
      unsigned vw_getEnumTag(const OpaqueValue *value) const {
        return getValueWitnesses()->_asEVWT()->getEnumTag(const_cast<OpaqueValue*>(value), this);
      }
      void vw_destructiveProjectEnumData(OpaqueValue *value) const {
        getValueWitnesses()->_asEVWT()->destructiveProjectEnumData(value, this);
      }
      void vw_destructiveInjectEnumTag(OpaqueValue *value, unsigned tag) const {
        getValueWitnesses()->_asEVWT()->destructiveInjectEnumTag(value, tag, this);
      }
    
      size_t vw_size() const {
        return getValueWitnesses()->getSize();
      }
    
      size_t vw_alignment() const {
        return getValueWitnesses()->getAlignment();
      }
    
      size_t vw_stride() const {
        return getValueWitnesses()->getStride();
      }
    
      unsigned vw_getNumExtraInhabitants() const {
        return getValueWitnesses()->getNumExtraInhabitants();
      }
    
      /// Allocate an out-of-line buffer if values of this type don't fit in the
      /// ValueBuffer.
      /// NOTE: This is not a box for copy-on-write existentials.
      OpaqueValue *allocateBufferIn(ValueBuffer *buffer) const;
    
      /// Get the address of the memory previously allocated in the ValueBuffer.
      /// NOTE: This is not a box for copy-on-write existentials.
      OpaqueValue *projectBufferFrom(ValueBuffer *buffer) const;
    
      /// Deallocate an out-of-line buffer stored in 'buffer' if values of this type
      /// are not stored inline in the ValueBuffer.
      void deallocateBufferIn(ValueBuffer *buffer) const;
    
      // Allocate an out-of-line buffer box (reference counted) if values of this
      // type don't fit in the ValueBuffer.
      // NOTE: This *is* a box for copy-on-write existentials.
      OpaqueValue *allocateBoxForExistentialIn(ValueBuffer *Buffer) const;
    
      // Deallocate an out-of-line buffer box if one is present.
      void deallocateBoxForExistentialIn(ValueBuffer *Buffer) const;
    
      /// Get the nominal type descriptor if this metadata describes a nominal type,
      /// or return null if it does not.
      ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>
      getTypeContextDescriptor() const {
        switch (getKind()) {
        case MetadataKind::Class: {
          if (Runtime::ObjCInterop) {
            const auto cls = static_cast<const TargetClassMetadata<
                Runtime, TargetAnyClassMetadataObjCInterop<Runtime>> *>(this);
            if (!cls->isTypeMetadata())
              return nullptr;
            if (cls->isArtificialSubclass())
              return nullptr;
            return cls->getDescription();
          } else {
            const auto cls = static_cast<const TargetClassMetadata<
                Runtime, TargetAnyClassMetadata<Runtime>> *>(this);
            if (!cls->isTypeMetadata())
              return nullptr;
            if (cls->isArtificialSubclass())
              return nullptr;
            return cls->getDescription();
          }
        }
        case MetadataKind::Struct:
        case MetadataKind::Enum:
        case MetadataKind::Optional:
          return static_cast<const TargetValueMetadata<Runtime> *>(this)
              ->Description;
        case MetadataKind::ForeignClass:
          return static_cast<const TargetForeignClassMetadata<Runtime> *>(this)
              ->Description;
        default:
          return nullptr;
        }
      }
    
      /// Get the class object for this type if it has one, or return null if the
      /// type is not a class (or not a class with a class object).
      const typename Runtime::template TargetClassMetadata<Runtime> *
      getClassObject() const;
    
      /// Retrieve the generic arguments of this type, if it has any.
      ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *
      getGenericArgs() const {
        auto description = getTypeContextDescriptor();
        if (!description)
          return nullptr;
    
        auto generics = description->getGenericContext();
        if (!generics)
          return nullptr;
    
        auto asWords = reinterpret_cast<
          ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *>(this);
        return asWords + description->getGenericArgumentOffset();
      }
    
      bool satisfiesClassConstraint() const;
    
      const TypeContextDescriptor *getDescription() const;
    
      bool isStaticallySpecializedGenericMetadata() const;
    
      bool isCanonicalStaticallySpecializedGenericMetadata() const;
    
    #if SWIFT_OBJC_INTEROP
      /// Get the ObjC class object for this type if it has one, or return null if
      /// the type is not a class (or not a class with a class object).
      /// This is allowed for InProcess values only.
      template <typename R = Runtime>
      typename std::enable_if<std::is_same<R, InProcess>::value, Class>::type
      getObjCClassObject() const {
        return reinterpret_cast<Class>(
            const_cast<TargetClassMetadata<
                InProcess, TargetAnyClassMetadataObjCInterop<InProcess>> *>(
                getClassObject()));
      }
    #endif
    
    #ifndef NDEBUG
      LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
                                "Only meant for use in the debugger");
    #endif
    
    protected:
      friend struct TargetOpaqueMetadata<Runtime>;
      
      /// Metadata should not be publicly copied or moved.
      constexpr TargetMetadata(const TargetMetadata &) = default;
      TargetMetadata &operator=(const TargetMetadata &) = default;
      constexpr TargetMetadata(TargetMetadata &&) = default;
      TargetMetadata &operator=(TargetMetadata &&) = default;
    };
    

    TargetEnumMetadata 继承于 TargetValueMetadata 继承于 TargetMetadata; 同时要注意 TargetRelativeDirectPointer数据结构是相对地址信息 - 存储的是偏移量。(只粘贴了部分源码,自行下载源码看着分析就得出)

    TargetEnumMetadata的数据结构:

    // 枚举Metadata
    struct TargetEnumMetadata {
        var kind: Int
        var typeDescriptor: UnsafeMutablePointer<TargetEnumDescriptor>
    }
    
    // 枚举描述器
    struct TargetEnumDescriptor {
        var flags: Int32
        var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
        var name: TargetRelativeDirectPointer<CChar>
        var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
        var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
        var NumPayloadCasesAndPayloadSizeOffset: UInt32
        var NumEmptyCases: UInt32
    }
    
    // 相对地址信息
    struct TargetRelativeDirectPointer<Pointee> {
        var offset: Int32 // 存储偏移量
        
        // 获取相对偏移指针
        mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee>{
            let offset = self.offset
            
            return withUnsafePointer(to: &self) { p in
               return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))
            }
        }
    }
    
    // 属性描述器
    struct FieldDescriptor {
        var MangledTypeName: TargetRelativeDirectPointer<CChar> 
        var Superclass: TargetRelativeDirectPointer<CChar>
        var kind: UInt16
        var fieldRecordSize: Int16
        var numFields: Int32 // 属性个数
        var fields: FiledRecordBuffer<FieldRecord> // 属性列表
    }
    
    // 属性
    struct FieldRecord {
        var fieldRecordFlags: Int32 // flags
        var mangledTypeName: TargetRelativeDirectPointer<CChar> // 属性类型
        var fieldName: TargetRelativeDirectPointer<UInt8> // 属性名称
    }
    
    struct FiledRecordBuffer<Element>{
        var element: Element
        
        mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
            return withUnsafePointer(to: &self) {
                let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
                    return start
                }
                return UnsafeBufferPointer(start: ptr, count: n)
            }
        }
        
        mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
            return withUnsafePointer(to: &self) {
                return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
            }
        }
    }
    

    注意:TargetRelativeDirectPointer是相对地址信息,比如说TargetEnumDescriptor里的name存储的是相对于当前对象的偏移量,通过这个偏移量找到真实的内容

    那么我们设计出了EnumMetadata,该如何使用呢?请看举例:
    自定义一个枚举类 TerminalChar

    enum TerminalChar {
        case plain(Bool)
        case bold
        case empty
        case cursor
    }
    

    通过按位转换成指针 UnsafeMutablePointer<TargetEnumMetadata>,就可以对指针进行操作了(给个小案例叭,请自己运行看结果):

    // 元类 Metadata
    // var clazz = TerminalChar.self
    // 使用按位转换成指针去操作(当前的元类clazz 就是 TargetEnumMetadata 这个结构体)
    let enumMetadata_ptr = unsafeBitCast(TerminalChar.self as Any.Type, to: UnsafeMutablePointer<TargetEnumMetadata>.self)
    
    let namePtr = enumMetadata_ptr.pointee.typeDescriptor.pointee.name.getmeasureRelativeOffset()
    print(String(cString: namePtr)) // TerminalChar
    print(enumMetadata_ptr.pointee.typeDescriptor.pointee.NumPayloadCasesAndPayloadSizeOffset) // 1
    print(enumMetadata_ptr.pointee.typeDescriptor.pointee.NumEmptyCases) // 3
    
    // 拿到属性描述器指针
    let fieldDesc_ptr = enumMetadata_ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset()
    print(String(cString: fieldDesc_ptr.pointee.MangledTypeName.getmeasureRelativeOffset()))
    print(String(cString: fieldDesc_ptr.pointee.Superclass.getmeasureRelativeOffset()))
    print(fieldDesc_ptr.pointee.kind) // 2
    print(fieldDesc_ptr.pointee.fieldRecordSize) // 12
    print(fieldDesc_ptr.pointee.numFields) // 4
    print(String(cString: fieldDesc_ptr.pointee.fields.index(of: 0).pointee.fieldName.getmeasureRelativeOffset())) // plain
    

    注意:
    let enumMetadata_ptr = unsafeBitCast(clazz as Any.Type, to: UnsafeMutablePointer<TargetEnumMetadata>.self)这句代码为什么一定要把 TerminalChar.self 强转成 Any.Type

    unsafeBitCast需要两个参数的内存大小相同。必须使用:TerminalChar.self as Any.Type进行转换,因为根据测试发现TerminalChar.self获取内存大小为0(这个地方是真的坑),先来看看MemoryLayout输出结果:

    番外小知识 unsafeBitCast 举例

    var age = 10
    var age1 = unsafeBitCast(age, to: Double.self)
    print(age1) // 5e-323
    

    注意:unsafeBitCast(age, to: Double.self)中的age是以二进制位的方式塞进Double类型里边,本质上age1上存储的是0xa,当print(age1)的时候是输出科学技术的Double。来看看 x/8g 后的 age1:

    unsafeBitCast

    言归正传!上面那个小案例可以把TerminalCharenum类的属性输出出来了,试想一下,我们是不是可以从源码得出StructMetadata,从而把一个结构体对象的属性内容打印出来。

    如果你想学习ClassMetadataStructMetadata和更详细的EnumMetadata,可以查看我分享的这篇文章

    相关文章

      网友评论

        本文标题:Swift进阶-Mirror解析

        本文链接:https://www.haomeiwen.com/subject/efglcrtx.html