How to extend float3 or any other built-in type to conform to the Codable protocol?

前端 未结 3 914
感动是毒
感动是毒 2021-01-18 15:14

In trying to serialize an array of float3 objects with the basic JSONEncoder, it\'s revealed that float3 does not conform to the Codable protocol, so this cannot be done.

3条回答
  •  旧时难觅i
    2021-01-18 15:58

    Dávid is correct on how to fix the problem, but it's worth understanding why it's a problem (it's not actually designated vs convenience initializers; that only applies to classes).

    If we created our own version of float3, your code would work fine with an extension:

    struct float3 {
        var x: Float
        var y: Float
        var z: Float
    }
    
    extension float3: Codable {
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            x = try values.decode(Float.self, forKey: .x)
            y = try values.decode(Float.self, forKey: .y)
            z = try values.decode(Float.self, forKey: .z)
        }
        // ...
    }
    

    So that seems strange. Why doesn't our implementation of the simd type work the same as the simd type? Because simd doesn't have an x stored property (or y or z). Those are all computed properties.

    The real interface is defined in simd.swift.gyb. If you study that code, you'll see all the SIMD vector types use a generic _vector storage:

    public var _vector: Builtin.${llvm_vectype}
    

    And then there are computed properties defined for each letter (component is ['x','y','z','w']):

    % for i in xrange(count):
      public var ${component[i]} : ${scalar} {
        @_transparent
        get {
          let elt = Builtin.${extractelement}(_vector,
            (${i} as Int32)._value)
    
          return ${scalar}(_bits: elt)
        }
        @_transparent
        set {
          _vector = Builtin.${insertelement}(_vector,
            newValue._value,
            (${i} as Int32)._value)
        }
      }
    % end
    

    So if we were building our own float3 (without fancy builtins), it'd be something like this:

    struct float3 {
        private var vector: [Float]
        var x: Float { get { return vector[0] } set { vector[0] = newValue } }
        var y: Float { get { return vector[1] } set { vector[1] = newValue } }
        var z: Float { get { return vector[2] } set { vector[2] = newValue } }
        init(x: Float, y: Float, z: Float) {
            vector = [x, y, z]
        }
    }
    

    And if you write your extension against that, you'll get the same error.

提交回复
热议问题