flapigen-rs
flapigen-rs copied to clipboard
[u8] slices to Java?
I see that [i8] maps to a JavaByteArray, but [u8] slices don't seem implemented. Is there a way to implement this?
I'm sorry to be late with the reply. For some reason, github did not show activity in my personal projects on my personal page. And I just got to my post today.
I suppose this is possible, but will require some additional CPU cycles. Because of Java has no primitive unsigned types. So all u8
types I have to convert to i16
(Rust) = short
(Java). That is why rust_swig
have no such feature by default.
I actually mean where you go from [u8] (byte slice) to JavaByteArray
, but I guess there are two interpretations here. No worries with the delay, no urgency here.
I actually mean where you go from [u8] (byte slice) to JavaByteArray
rust_swig was made extensible, because of always there is specific for project types mapping.
So you can create you own SwigInto/SwigFrom implementation to convert to/from [u8] slice, and use rust_swig::Generator::merge_type_map
to extend knowledge of rust_swig
about your custom type conversation rules.
And after merging your custom type rules with standard one rust_swig
converts all your method with -> &[u8]
to any Java type that you want.
As example you can look for macroslib/src/java_jni/jni-include.rs
impl<'a> SwigInto<jbyteArray> for &'a [i8] {
fn swig_into(self, env: *mut JNIEnv) -> jbyteArray {
JavaByteArray::from_slice_to_raw(self, env)
}
}
and it is not only code that rust_swig insert into your project if you return [i8] slice
,
but this is also instruction to rust_swig how to handle such type as type of return value.
I have the same problem. So I expand the type rules using following file:
mod swig_foreign_types_map {}
impl SwigDeref for JavaByteArray {
type Target = [u8];
fn swig_deref(&self) -> &Self::Target {
self.to_slice()
}
}
impl SwigFrom<jbyteArray> for JavaByteArray {
fn swig_from(x: jbyteArray, env: *mut JNIEnv) -> Self {
JavaByteArray::new(env, x)
}
}
impl<'a> SwigInto<jbyteArray> for &'a [u8] {
fn swig_into(self, env: *mut JNIEnv) -> jbyteArray {
JavaByteArray::from_slice_to_raw(self, env)
}
}
Is it okay to reuse JavaByteArray both for i8 and u8?
@VMatrix1900
Is it okay to reuse JavaByteArray both for i8 and u8?
It depend on your java code, if it is ok for you to pass 255
to u8 in Rust,
and get -1
in Java then ok, in other case better to use short []
Java type for u8
array,
or use some opaque java class to convert internal byte
from byte []
to short
I don't think the conversion via short
is necessary - I've always done reinterpret_cast<unsigned char>(signed_char)
and vice-versa with no problems. AFAIK so long as we don't edit the bits (e.g. by incrementing it), the "byte" value we care about stays the same.
N.B. I've never coded for a platform where sizeof(char)
is not 1
. I have no experience to know if the same thing is safe in that case.
What's the easiest way to simply do a cast like that so we can get [u8]
/Vec<u8>
support?
I've always done reinterpret_cast
(signed_char) and vice-versa with no problems
Not sure what do you mean, this is issue related to Java only, for C++ u8 support is just fine. There are no unsigned integer types in Java. So on Java side this data will be useless, what point to return integer that impossible to use?
In my case I care about it as a vector of bytes as opposed to a vector of integers. I don’t want the compiler or CPU to care about signedness. It’s just 8 bits of info. That’s sorta the essence of byte arrays in Java and why C++17 got std::byte
(Though the implementation of the latter leaves a lot to be desired, but that’s a completely other topic!)
I’m new to Rust, but everywhere seems to use u8
for bytes like this. So in my case where I want to move an arbitrary vector of bytes (eg PNG representation of an image), it feels most natural for me to be able to expose it as Vec<u8>
because that’s what Rust code is using under the hood. The fact that jByteArray’a C type is a signed char is ideally invisible.
Or maybe I’m missing something totally here too!
So in my case where I want to move an arbitrary vector of bytes
This issue is about common case, type conversations rule that possible to use for every one.
The specific rule should be part of your project, not part of rust_swig, via your custom "type map" https://docs.rs/rust_swig/0.4.0/rust_swig/struct.Generator.html#method.merge_type_map , or you can defined type conversation rules just in .rs.in
file.
You can a bunch of options for this, for example define rule that std::mem::transmutate
Vecto
Vec
Hey,
I haven't managed to figure out how to do it. I tried using @VMatrix1900's solution but I'm still getting errors:
error: Do not know conversation from Java type to such rust type '& [ u8 ]'
fn Collection::set_content(&mut self, content: &[u8]) -> Result<()>;
Update: that's what I ended up using (which works):
foreign_typemap!(
($p:r_type) Vec<u8> => jbyteArray {
let slice = &($p)[..];
let slice = unsafe { std::mem::transmute::<&[u8], &[i8]>(slice) };
let raw = JavaByteArray::from_slice_to_raw(slice, env);
$out = raw;
};
($p:f_type) => "jbyteArray";
);
foreign_typemap!(
($p:r_type) &'a [u8] => jbyteArray {
let slice = unsafe { std::mem::transmute::<&[u8], &[i8]>($p) };
let raw = JavaByteArray::from_slice_to_raw(slice, env);
$out = raw;
};
($p:f_type) => "jbyteArray";
($p:r_type) &'a [u8] <= jbyteArray {
let arr = JavaByteArray::new(env, $p);
let slice = arr.to_slice();
let slice = unsafe { std::mem::transmute::<&[i8], &[u8]>(slice) };
$out = slice;
};
($p:f_type) <= "jbyteArray";
);