1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use std::iter;
use syn::{
parse_quote, FnArg, Pat, PatIdent, PatType, Path, PathArguments, Signature, Type,
TypeReference,
};
use proc_macro_error::emit_error;
pub fn canonicalize_path(path: &Path) -> Path {
let mut result = path.clone();
result.segments = result
.segments
.into_iter()
.map(|mut seg| {
seg.arguments = PathArguments::None;
seg
})
.collect();
result
}
pub fn is_self_method(signature: &Signature) -> bool {
signature.inputs.iter().any(|i| match i {
FnArg::Receiver(_) => true,
FnArg::Typed(t) => match &*t.pat {
Pat::Ident(PatIdent { ident, .. }) => ident == "self",
_ => false,
},
})
}
pub fn get_env_arg(signature: Signature) -> (Signature, Option<FnArg>) {
let self_method = is_self_method(&signature);
let possible_env_arg = if !self_method {
signature.inputs.iter().next()
} else {
signature.inputs.iter().nth(1)
};
let has_explicit_env_arg = if let Some(FnArg::Typed(PatType { ty, .. })) = possible_env_arg {
if let Type::Reference(TypeReference { elem, .. }) = &**ty {
if let Type::Path(t) = &**elem {
let full_path: Path = parse_quote! { ::robusta_jni::jni::JNIEnv };
let imported_path: Path = parse_quote! { JNIEnv };
let canonicalized_type_path = canonicalize_path(&t.path);
canonicalized_type_path == imported_path || canonicalized_type_path == full_path
} else {
false
}
} else if let Type::Path(t) = &**ty {
let full_path: Path = parse_quote! { ::robusta_jni::jni::JNIEnv };
let imported_path: Path = parse_quote! { JNIEnv };
let canonicalized_type_path = canonicalize_path(&t.path);
if canonicalized_type_path == imported_path || canonicalized_type_path == full_path {
emit_error!(t, "explicit environment parameter must be of type `&JNIEnv`");
}
false
} else {
false
}
} else {
false
};
let (transformed_signature, env_arg): (Signature, Option<FnArg>) = if has_explicit_env_arg {
let mut inner_signature = signature;
let mut iter = inner_signature.inputs.into_iter();
if self_method {
let self_arg = iter.next();
let env_arg = iter.next();
inner_signature.inputs = iter::once(self_arg.unwrap()).chain(iter).collect();
(inner_signature, env_arg)
} else {
let env_arg = iter.next();
inner_signature.inputs = iter.collect();
(inner_signature, env_arg)
}
} else {
(signature, None)
};
(transformed_signature, env_arg)
}
pub fn get_abi(sig: &Signature) -> Option<String> {
sig
.abi
.as_ref()
.and_then(|l| l.name.as_ref().map(|n| n.value()))
}