I have been in the same boat the last few days. I eventually came out with a general scheme to deal with C Arrays in C structs from C API, good if one has to deal with large arrays, but it must make use of "unsafeBitCast()". Also it must be adapted for each single fixed C array. This is the adaption to answer the current question (the code has been tested and it is working):
// This is our C array in this case char[8]
typealias CArray8Chars = (
CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar
)
let zero8Chars: CArray8Chars = (
0, 0, 0, 0, 0, 0, 0, 0
)
struct CString8 {
private var value: CArray8Chars = zero8Chars
var asString: String {
mutating get {
var cString = [CChar]()
for i in 0..<sizeofValue(value) {
cString += [self[i]]
if self[i] == 0 {
break
}
}
return String.fromCStringRepairingIllFormedUTF8(&cString).0!
}
set {
let cchars = Array(newValue.utf8).map { CChar(Int8(bitPattern: UInt8($0))) }
for i in 0..<min(cchars.count,sizeof(CArray8Chars))-1 { self[i] = cchars[i] }
self[min(cchars.count,sizeof(CArray8Chars))-1] = 0
}
}
subscript(i: Int) -> CChar {
mutating get {
let bytePtr = withUnsafePointer(&value, { (ptr) -> UnsafePointer<CChar> in
return unsafeBitCast(ptr, UnsafePointer<CChar>.self)
})
return bytePtr[i]
}
set {
let bytePtr = withUnsafeMutablePointer(&value, { (ptr) -> UnsafeMutablePointer<CChar> in
return unsafeBitCast(ptr, UnsafeMutablePointer<CChar>.self)
})
bytePtr[i] = newValue
}
}
}
Now in the case of the motorcycle C struct it will be as following:
struct MotorCycle {
var mfg = CString8()
var model = CString8()
}
var cycle = MotorCycle()
GetMotorcycle(&cycle)
var manufacturer = cycle.mfg.asString // Since the string comes from C it works fine
This also allows to set mfg/model using Unicode strings, but with a caveat:
// "💖" utf8 encoding makes the C string too big, so it gets cut. What's left represents an unknown char
cycle.model.asString = "I do 💖 Motor Bikes"
println(cycle.model.asString)
and makes the tuples indexable:
println(cycle.mfg[2])
cycle.model[2] = 32 // space. They are CChars, thus Int8
If one likes CString8 can be further extended, allowing to get/set substrings and the likes. But that's beyond the scope of this question.