There is a tuple of UInt8's in a struct MIDIPacket. Normal assignment is like this:
import CoreMIDI
let packet = MIDIPacket()
packet.data.0 = 0x02
packet.data.1 = 0x5f
and so on.
This tuple has length of ~128+. There is an array of values, converted, which I would like to assign to the packet beginning at a certain index.
let converted = [0x01, 0x02, 0x5e,...]
var k = packet starting index of assignment
for i in 0..<converted.count {
packet.data(k) = converted[i]
k += 1
}
How do I do this?
subscripting doesn't work: e.g. packet.data[i], while I believe Mirror simply creates a copy of the packet, so assigning to it would not work..
let bytes = Mirror(reflecting: packet.data).children;
for (_, b) in bytes.enumerated() {
}
There's no official API for doing this, but IIRC, tuples of homogeneous element types are guaranteed to have a contiguous memory layout. You take advantage of this by using UnsafeBufferPointer to read/write to the tuple.
Usually this requires you to manually hard-code the tuple's element count, but I wrote some helper functions that can do this for you. There's two variants, a mutable one, which lets you obtain an UnsafeBufferPointer, which you can read (e.g. to create an Array), and a mutable one, which gives you a UnsafeMutableBufferPointer, through which you can assign elements.
enum Tuple {
static func withUnsafeBufferPointer<Tuple, TupleElement, Result>(
to value: Tuple,
element: TupleElement.Type,
_ body: (UnsafeBufferPointer<TupleElement>) throws -> Result
) rethrows -> Result {
try withUnsafePointer(to: value) { tuplePtr in
let count = MemoryLayout<Tuple>.size / MemoryLayout<TupleElement>.size
return try tuplePtr.withMemoryRebound(
to: TupleElement.self,
capacity: count
) { elementPtr in
try body(UnsafeBufferPointer(start: elementPtr, count: count))
}
}
}
static func withUnsafeMutableBufferPointer<Tuple, TupleElement, Result>(
to value: inout Tuple,
element: TupleElement.Type,
_ body: (UnsafeMutableBufferPointer<TupleElement>) throws -> Result
) rethrows -> Result {
try withUnsafeMutablePointer(to: &value) { tuplePtr in
let count = MemoryLayout<Tuple>.size / MemoryLayout<TupleElement>.size
return try tuplePtr.withMemoryRebound(
to: TupleElement.self,
capacity: count
) { elementPtr in
try body(UnsafeMutableBufferPointer(start: elementPtr, count: count))
}
}
}
}
var destinationTouple: (Int, Int, Int, Int) = (0, 0, 0, 0) // => (0, 0, 0, 0)
var sourceArray = Array(1...4)
print("before:", destinationTouple)
Tuple.withUnsafeMutableBufferPointer(to: &destinationTouple, element: Int.self) { (destBuffer: UnsafeMutableBufferPointer<Int>) -> Void in
sourceArray.withUnsafeMutableBufferPointer { sourceBuffer in
// buffer[...] = 1...
destBuffer[destBuffer.indices] = sourceBuffer[destBuffer.indices]
return ()
}
}
print("after:", destinationTouple) // => (1, 2, 3, 4)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With