This may be an old question, but since it was asking in the context of Core Audio, I just wanted to share a variant I was playing with.
For Core Audio, where some (but not all?) OSStatus
/Int32
values are defined using four characters, some code from Apple's old Core Audio Utility Classes can provide inspiration (very similar to the linked question)
From CAXException.h
:
class CAX4CCStringNoQuote {
public:
CAX4CCStringNoQuote(OSStatus error) {
// see if it appears to be a 4-char-code
UInt32 beErr = CFSwapInt32HostToBig(error);
char *str = mStr;
memcpy(str, &beErr, 4);
if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) {
str[4] = '\0';
} else if (error > -200000 && error < 200000)
// no, format it as an integer
snprintf(str, sizeof(mStr), "%d", (int)error);
else
snprintf(str, sizeof(mStr), "0x%x", (int)error);
}
const char *get() const { return mStr; }
operator const char *() const { return mStr; }
private:
char mStr[16];
};
In Swift 5, one rough translation (without the hex representation for large values) might be:
private func osStatusToString(_ value: OSStatus) -> String {
let data = withUnsafeBytes(of: value.bigEndian, { Data($0) })
// If all bytes are printable characters, we treat it like characters of a string
if data.allSatisfy({ 0x20 <= $0 && $0 <= 0x7e }) {
return String(data: data, encoding: .ascii)!
} else {
return String(value)
}
}
Note that the Data
initializer is making a copy of the bytes, though it may be possible to avoid that if desired.
Of course, with Core Audio we encounter four character codes with both Int32
and UInt32
types. I haven't done generics with Swift before, but one way to handle them in a single function could be:
private func stringifyErrorCode<T: FixedWidthInteger>(_ value: T) -> String {
let data = withUnsafeBytes(of: value.bigEndian, { Data($0) })
// If all bytes are printable characters, we treat it like characters of a string
if data.allSatisfy({ 0x20 <= $0 && $0 <= 0x7e }) {
return String(data: data, encoding: .ascii)!
} else {
return String(value, radix: 10)
}
}
This may not be suitable for general purpose handling of four character codes (I've seen other answers that support characters in the MacOS Roman encoding versus ASCII in the example above. There's likely some history there I'm not aware of), but may be reasonable for Core Audio status/selector codes.