A have a structure like this (defined in bson.h of mongodb c driver):
typedef struct
{
uint32_t domain;
uint32_t code;
char message[504];
} bson_error_t;
In Swift I have a pointer to this structure like this:
err: UnsafePointer<bson_error_t> = ...
Now whatever I do I cannot convert message[504]
(which Swift sees as a tuple of (Int8, Int8, Int8, ...504 times)) to char*
to use it in String.fromCString().
Is it even possible to do that in Swift? As a temporary solution I created a helper C function in a separate .c
file which takes err *bson_error_t
and returns char*
, but this is weird if
Swift cannot do it by itself.
It's not pretty, not intuitive, but it's doable. Purely in Swift, no C glue code needed. A minimal demo:
b.h
typedef struct {
int n;
char s[8];
} Bridged;
Bridged *make_b(void);
b.c
#include <stdlib.h>
#include <string.h>
#include "b.h"
Bridged *make_b(void)
{
Bridged *p = calloc(sizeof(*p), 1);
memcpy(p->s, "foobarz", 8);
return p;
}
b.swift:
// half compile-time, half run-time black magic
func toCharArray<T>(t: T) -> [CChar] {
var a: [CChar] = []
let mirror = reflect(t)
for i in 0 ..< mirror.count {
a.append(mirror[i].1.value as CChar)
}
return a
}
let b = make_b().memory.s // bridged tuple of 8 chars
let a = toCharArray(b) // Swift array of (8) CChars
let s = String.fromCString(a) // proper Swift string
println(s)
Compile:
$ xcrun swiftc -O -c b.swift -import-objc-header b.h
$ clang -O2 -c b.c -o b.c.o
$ xcrun swiftc b.o b.c.o -o b
Run:
$ ./b
Optional("foobarz")
Here my suggestion (similar to rintaro's approach, perhaps slightly simpler):
var err: UnsafeMutablePointer<bson_error_t> = ...
var msg = err.memory.message
let msgString = withUnsafePointer(&msg) { String.fromCString(UnsafePointer($0)) }
println(msgString)
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