First of all, thank you very much for this example project! It really helped me get started on using Rust from Java.
As for the problem, greetings.rs defines GreetingSet as follows:
pub struct GreetingSet {
// A pointer to an array of Greetings. This is converted to a Greeting.ByReference by JNA.
greetings: Box<[Greeting]>,
// The size of the array. We need to pass it back to Java so that we know how long the array
// is (JNA can't guess the size). We need to do this with all arrays created in Java and read
// in Rust (or vise-versa). This c_int is converted to a Java int by JNA.
number_of_greetings: c_int
}
This is actually incorrect. It won't crop up if you have a single GreetingSet, but if you had a contiguous array of them, you would run into problems.
The issue is apparent when you check mem::size_of::<GreetingSet>(). On a 64-bit platform, you probably expect it to be 16: 8 for the pointer, 4 for the int, and another 4 for alignment. If you test it out, though, it will actually be 24!
It turns out that the Box<[Greeting]> is basically a struct, itself: it contains the 8-byte pointer, and an 8-byte usize size field. Then, GreetingSet (as it's currently defined) tacks on a redundant 4-byte size and 4 bytes for alignment. JNA is already reading the size as provided by the Box<[]>, not your number_of_greetings field (you can test it out by putting a junk value in there).
To sum it up, GreetingSet on the Rust side should look like this:
pub struct GreetingSet {
// A struct that includes a pointer to an array of Greetings and a size. JNA will convert this
// to two fields: a Greeting.ByReference and an int.
greetings: Box<[Greeting]>,
}
As the updated comment indicates, the Java code remains the same. You could optionally use a size-dependent type (com.sun.jna.IntegerType?), but Java will break on arrays longer than Integer.MAX_VALUE, anyway.
Without this change, JNA expects GreetingSetto be 16 bytes in length, but as indicated above, it's actually 24 bytes, and this leads to improper alignment if you have a GreetingSet[].
In case it's relevant, I tested this behavior on Rust nightly (1.4).
First of all, thank you very much for this example project! It really helped me get started on using Rust from Java.
As for the problem, greetings.rs defines
GreetingSetas follows:This is actually incorrect. It won't crop up if you have a single
GreetingSet, but if you had a contiguous array of them, you would run into problems.The issue is apparent when you check
mem::size_of::<GreetingSet>(). On a 64-bit platform, you probably expect it to be 16: 8 for the pointer, 4 for the int, and another 4 for alignment. If you test it out, though, it will actually be 24!It turns out that the
Box<[Greeting]>is basically a struct, itself: it contains the 8-byte pointer, and an 8-byteusizesize field. Then,GreetingSet(as it's currently defined) tacks on a redundant 4-byte size and 4 bytes for alignment. JNA is already reading the size as provided by theBox<[]>, not yournumber_of_greetingsfield (you can test it out by putting a junk value in there).To sum it up,
GreetingSeton the Rust side should look like this:As the updated comment indicates, the Java code remains the same. You could optionally use a size-dependent type (
com.sun.jna.IntegerType?), but Java will break on arrays longer thanInteger.MAX_VALUE, anyway.Without this change, JNA expects
GreetingSetto be 16 bytes in length, but as indicated above, it's actually 24 bytes, and this leads to improper alignment if you have aGreetingSet[].In case it's relevant, I tested this behavior on Rust nightly (1.4).