Skip to content

Commit

Permalink
Fix convert for structs with both data and class fields, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
uvlad7 committed Mar 19, 2024
1 parent bc3fb1e commit 6182ca0
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 11 deletions.
12 changes: 8 additions & 4 deletions robusta-codegen/src/derive/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ fn from_java_value_macro_derive_impl(input: DeriveInput) -> syn::Result<TokenStr
})
.collect();

let mut fields_struct_init = data_fields_struct_init.clone();
fields_struct_init.extend(class_fields_struct_init);

Ok(quote! {
#instance_field_type_assertion

Expand All @@ -191,8 +194,7 @@ fn from_java_value_macro_derive_impl(input: DeriveInput) -> syn::Result<TokenStr

Self {
#instance_ident: ::robusta_jni::convert::Local::new(env, source),
#(#data_fields_struct_init),*
#(#class_fields_struct_init),*
#(#fields_struct_init),*
}
}
}
Expand Down Expand Up @@ -252,6 +254,9 @@ fn tryfrom_java_value_macro_derive_impl(input: DeriveInput) -> syn::Result<Token
}
}).collect();

let mut fields_struct_init = data_fields_struct_init.clone();
fields_struct_init.extend(class_fields_struct_init);

Ok(quote! {
#instance_field_type_assertion

Expand All @@ -265,8 +270,7 @@ fn tryfrom_java_value_macro_derive_impl(input: DeriveInput) -> syn::Result<Token

Ok(Self {
#instance_ident: ::robusta_jni::convert::Local::new(env, source),
#(#data_fields_struct_init),*
#(#class_fields_struct_init),*
#(#fields_struct_init),*
})
}
}
Expand Down
11 changes: 10 additions & 1 deletion tests/driver/native/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl<'env: 'borrow, 'borrow> FromJavaValue<'env, 'borrow> for StringArr {
pub mod jni {
use std::convert::TryInto;

use robusta_jni::convert::Field;
use robusta_jni::convert::{IntoJavaValue, FromJavaValue, JValueWrapper, Signature, ArrSignature, TryFromJavaValue, TryIntoJavaValue};
use robusta_jni::convert::Local;
use robusta_jni::jni::errors::Result as JniResult;
Expand All @@ -68,7 +69,9 @@ pub mod jni {
pub struct User<'env: 'borrow, 'borrow> {
#[instance]
raw: Local<'env, 'borrow>,
password: String,
#[field]
pub username: Field<'env, 'borrow, String>,
pub password: String,
}

impl<'env: 'borrow, 'borrow> User<'env, 'borrow> {
Expand Down Expand Up @@ -519,6 +522,12 @@ pub mod jni {
user_arr_nullable2: Option<Box<[Self]>>,
) -> Vec<String> {}

#[call_type(unchecked)]
pub extern "java" fn cloneUser(
env: &'borrow JNIEnv<'env>,
user: &Self,
) -> Self {}

#[constructor]
pub extern "java" fn new(
env: &'borrow JNIEnv<'env>,
Expand Down
15 changes: 13 additions & 2 deletions tests/driver/src/main/java/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,16 @@ public List<String> selfSignatureCheck(
User[] box_option_user,
@Nullable User[] option_box_user1,
@Nullable User[] option_box_user2) {
borrow_user.username += "_";
borrow_user.password += "_";
if (option_borrow_user1 != null) option_borrow_user1.password += "_";
if (option_borrow_user2 != null) option_borrow_user2.password += "_";
if (option_borrow_user1 != null) {
option_borrow_user1.username += "_";
option_borrow_user1.password += "_";
}
if (option_borrow_user2 != null) {
option_borrow_user2.username += "_";
option_borrow_user2.password += "_";
}
return List.of(
this.toString(),
String.valueOf(user),
Expand Down Expand Up @@ -337,4 +344,8 @@ public List<String> selfSignatureCheckUnchecked(
vec_user, vec_option_user, option_vec_user1, option_vec_user2,
box_user, box_option_user, option_box_user1, option_box_user2);
}

public static User cloneUser(User user) {
return user;
}
}
16 changes: 12 additions & 4 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ fn vm_creation_and_object_usage() {
let res = u.selfSignatureCheck(
&env,
create_user("user", "42"),
&borrow_user, Some(&borrow_user_opt), Some(&borrow_user_opt),
&borrow_user, Some(&borrow_user_opt), Some(&borrow_user_opt),
Some(create_user("user", "null")), None,
vec![create_user("user", "pass")],
vec![Some(create_user("user", "null")), None],
Expand All @@ -225,7 +225,7 @@ fn vm_creation_and_object_usage() {
u.selfSignatureCheckUnchecked(
&env,
create_user("user", "42"),
&borrow_user, Some(&borrow_user_opt), Some(&borrow_user_opt),
&borrow_user, Some(&borrow_user_opt), Some(&borrow_user_opt),
Some(create_user("user", "null")), None,
vec![create_user("user", "pass")],
vec![Some(create_user("user", "null")), None],
Expand All @@ -245,9 +245,17 @@ fn vm_creation_and_object_usage() {
"[User{username='login', password='arr_null'}]", "null",
]
);
// Mutable data fields can be tricky, as data is copied only once
// when (Try)FromJavaValue is called
assert_eq!("42", borrow_user.password);
assert_eq!("42__", borrow_user.getPassword(&env).expect("unable to get password"));
// We actually reinitialize data field here
assert_eq!("42__", User::cloneUser(&env, &borrow_user).password);
// Mutable class fields work as expected
assert_eq!("borrow__", borrow_user.username.get().expect("unable to get username"));

assert_eq!(borrow_user.toString(&env), "User{username='borrow', password='42__'}");
assert_eq!(borrow_user_opt.toString(&env), "User{username='borrow_opt', password='42____'}");
assert_eq!(borrow_user.toString(&env), "User{username='borrow__', password='42__'}");
assert_eq!(borrow_user_opt.toString(&env), "User{username='borrow_opt____', password='42____'}");

let mut res = User::getStringArrNullable2D(
&env,
Expand Down

0 comments on commit 6182ca0

Please sign in to comment.