Create an advanced variadic extension for Data in swift

1

I wanted to append Different byte storage types like Int8, Int16, Int32, .. into data. It has become very complex as every time I have to convert one by one to data and append the same.

How to create extension for Data which will accept Int8, Int16, Int16 Int32 in any order and return bytes

Typically the below code should work. I tried but. not able to finish the extension method

let value1: Int8 = 0x01
let value2: Int16 = 0x0001
let value3: Int32 = 0x00000001

let data = Data.getBytes(value1, value2, value3)

extension Data {  
    static func getBytes(...) -> Data {
        // How to proceed?
    }  
}
ios
swift
asked on Stack Overflow Jan 27, 2020 by Saranjith • edited Jan 27, 2020 by Saranjith

1 Answer

1

First, you need a common type that will be accepted by getBytes. Unfortunately we cannot use FixedWidthInteger directly, because it contains a Self constraint. We cannot use FixedWidthInteger as a generic parameter either, because then we would not be able to mix Int8 and Int16 and so on in a single call.

Therefore, instead of using Any, I would suggest to introduce a new protocol MyIntType and let all the types you want to support implement this:

protocol MyIntType {
    // ...
}

extension Int8: MyIntType { }
extension Int16: MyIntType { }
extension Int32: MyIntType { }

extension Data {  
    static func getBytes(_ values : MyIntType...) -> Data { /* ... */ }
}

In getBytes, you need to access the internal bytes from the concrete Int-Type, e.g. call something like Data(bytes: &intValue, count: MemoryLayout<Int8>.size). Fortunately, Int8 etc. support something like bitWidth (which is similar to the MemoryLayout) because the all conform to the FixedWidthInteger protocol.

Nevertheless, we cannot use FixedWidthInteger directly in the getBytes function, because it contains a Self constraint.

As a work-around, we just need to add the bitWidth property to our MyIntType protocol:

protocol MyIntType  {
  var bitWidth:Int { get }
}

All those Intx-Types already implement it, so we do not need an extension for them, and can simply use it in getBytes:

extension Data {  
    static func getBytes (_ values:MyIntType...) -> Data {
        var d = Data()
        for var v in values {
            let data = Data(bytes:&v, count:v.bitWidth / 8)        
            d.append(contentsOf:data)
        }
        return d
    }  
}

Now we can check it:

let value1: Int8 = 0x01
let value2: Int16 = 0x0010
let value3: Int32 = 0x00000100

let bytes = Data.getBytes(value1, value2, value3)
print (bytes)
for b in bytes {
    print (b)
}
answered on Stack Overflow Jan 27, 2020 by Andreas Oetjen • edited Jan 27, 2020 by Andreas Oetjen

User contributions licensed under CC BY-SA 3.0