Hey! I am looking for some input what people think is the best approach to handling passing bytes between Swift and Java, when using the JNI jextract tool.
The problem
At this moment, the JExtract tool will extract any Swift UInt8 as Java’s byte, and therefore also [UInt8] as byte[]. Conversions between these two types just currently use the init(_source:) initializer, which will crash if the source is not within the valid range for the integer type.
The Swift type UInt8 is an unsigned byte, where as Java's byte is a signed byte. This will then mean Swift will crash if you try to pass a byte such as -1 to Swift.
Seing as [UInt8] is quite a common type to use in Swift to represent a bag-of-bytes, especially if you do not want to rely on Foundation, this is quite annoying for developers.
Possible solution
Instead of using the init(_source:) initializer, we could use init(bitPattern:), which will just use the underlying bits and perform no bounds checking. This would mean, if the Swift function you are calling into, relies on the numeric value of UInt8, it could lead to incorrect behaviour.
For example:
func printMyAge(_ age: UInt8) {
print("I am \(age) years old!")
}
printMyAge(10) // I am 10 years old!
printMyAge(UInt8(bitPattern: -10)) // I am 246 years old!
This might not be that much of an issue, since UInt8 is mostly used as a byte, and not as its numeric representation. So in my opinion, this would be a good solution. Also, byte and byte[] is the "standard" way to interact with a list of bytes in Java. And if we forced users to use something like Data instead, we put the extra burden of somewhat understanding Swift Data and instantiating it, in order to call these APIs.
How others do it.
The skip-tool JNI layer extracts Kotlin code and is therefore able to use Kotlin's unsigned types, which we cannot.
The FFM mode currently only interacts with Foundation.Data as the "bag-of-bytes" type.
The questions
- Do you think its a problem that we just use the bit-interpretation of
UInt8?- Should this be an opt-in mode?
- Any other ideas for solutions?
- Do you prefer that the APIs are exported using standard Java types such as
byteandbyte[], or would you be OK with having to use a customBagOfBytestype, such asFoundation.Data?