1mod utils;
15
16use proc_macro::TokenStream;
17
18use heck::ToLowerCamelCase;
19use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
20use quote::{quote, ToTokens};
21use syn::{
22 parse2, parse_macro_input, punctuated::Punctuated, Field, FieldMutability, Fields, FieldsNamed,
23 ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, LitInt, Token, TraitItem, Type,
24 TypeParamBound, Visibility,
25};
26
27use crate::utils::{get_object_return_value_token, get_result_token, get_return_value_token, parse_function_signature, ClassMetadata, FieldMetadata, InterfaceMetadata, MethodMetadata};
28
29#[proc_macro_attribute]
47pub fn java_class(attrs: TokenStream, input: TokenStream) -> TokenStream {
48 let attrs: ClassMetadata = parse2(Into::<TokenStream2>::into(attrs)).unwrap();
49 let cls = attrs.class_name;
50 let based = attrs.base_class;
51 let mut item = parse_macro_input!(input as ItemStruct);
52 let name = item.ident.clone();
53 let generics = item.generics.clone();
54 let mut item2 = item.clone();
55
56 let mut add_field_this = Field {
57 attrs: vec![],
58 vis: Visibility::Inherited,
59 mutability: FieldMutability::None,
60 ident: Some(Ident::new("_this", Span::call_site())),
61 colon_token: None,
62 ty: Type::Verbatim(quote! {droid_wrap_utils::GlobalRef}),
63 };
64 let mut add_field_super = Field {
65 attrs: vec![],
66 vis: Visibility::Inherited,
67 mutability: FieldMutability::None,
68 ident: Some(Ident::new("_based", Span::call_site())),
69 colon_token: None,
70 ty: Type::Verbatim(based.to_token_stream()),
71 };
72
73 let (fields, added_this, added_super, added_default) = match item.fields {
74 Fields::Named(mut f) => {
75 let mut added_default = TokenStream2::new();
76 for i in f.named.iter() {
77 let i = i.ident.clone();
78 added_default.extend(quote! {#i: fields.#i,});
79 }
80 f.named.push(add_field_this);
81 let added_super = if based.is_some() {
82 f.named.push(add_field_super);
83 quote! {_based}
84 } else {
85 quote!()
86 };
87 (Fields::Named(f), quote! {_this}, added_super, added_default)
88 }
89 Fields::Unnamed(mut f) => {
90 let mut added_default = TokenStream2::new();
91 for i in 0..f.unnamed.len() {
92 let i = LitInt::new(&i.to_string(), Span::call_site());
93 added_default.extend(quote! {#i: fields.#i,});
94 }
95 add_field_this.ident = None;
96 add_field_super.ident = None;
97 let len = LitInt::new(&f.unnamed.len().to_string(), Span::call_site());
98 let added_this = quote! {#len};
99 f.unnamed.push(add_field_this);
100 let added_super = if based.is_some() {
101 let len = LitInt::new(&f.unnamed.len().to_string(), Span::call_site());
102 f.unnamed.push(add_field_super);
103 quote! {#len}
104 } else {
105 quote!()
106 };
107 (Fields::Unnamed(f), added_this, added_super, added_default)
108 }
109 Fields::Unit => {
110 let mut fields = Punctuated::<Field, Token![,]>::new();
111 fields.push(add_field_this);
112 let added_super = if based.is_some() {
113 fields.push(add_field_super);
114 quote! {_based}
115 } else {
116 quote!()
117 };
118 (
119 Fields::Named(FieldsNamed {
120 brace_token: Default::default(),
121 named: fields,
122 }),
123 quote! {_this},
124 added_super,
125 quote!(),
126 )
127 }
128 };
129 item.fields = fields;
130
131 let build_self = if based.is_some() {
132 quote! {
133 Self {#added_this: this.clone(), #added_super: this.into(), #added_default }
134 }
135 } else {
136 quote! {
137 Self {#added_this:this.clone(), #added_default }
138 }
139 };
140
141 let (item2_token, name2) = if added_default.is_empty() {
142 (quote!(), quote! {()})
143 } else {
144 let name2 = Ident::new((name.to_string() + "Default").as_str(), Span::call_site());
145 item2.ident = name2.clone();
146 (quote! {#item2}, quote! {#name2})
147 };
148
149 let impl_based_deref = if based.is_some() {
150 quote! {
151 impl #generics std::ops::Deref for #name #generics {
152 type Target = #based;
153
154 fn deref(&self) -> &Self::Target {
155 &self.#added_super
156 }
157 }
158
159 impl #generics std::ops::DerefMut for #name #generics {
160 fn deref_mut(&mut self) -> &mut Self::Target {
161 &mut self.#added_super
162 }
163 }
164 }
165 } else {
166 quote! {
167 impl #generics std::ops::Deref for #name #generics {
168 type Target = droid_wrap_utils::GlobalRef;
169
170 fn deref(&self) -> &Self::Target {
171 &self.#added_this
172 }
173 }
174 }
175 };
176
177 let stream = quote! {
178 #item
179 #item2_token
180
181 impl #generics JObjNew for #name #generics {
182 type Fields = #name2;
183
184 fn _new(this: &droid_wrap_utils::GlobalRef, fields: Self::Fields) -> Self {
185 #build_self
186 }
187 }
188
189 impl #generics JType for #name #generics {
190 type Error = droid_wrap_utils::Error;
191 const CLASS: &'static str = #cls;
192 const OBJECT_SIG: &'static str = concat!("L", #cls, ";");
193 }
194
195 impl #generics JObjRef for #name #generics {
196 fn java_ref(&self) -> droid_wrap_utils::GlobalRef {
197 self.#added_this.clone()
198 }
199 }
200
201 impl #generics PartialEq for #name #generics {
202 fn eq(&self, other: &Self) -> bool {
203 let r = self.java_ref();
204 let t = other.java_ref();
205 if r.is_null() && t.is_null() {
206 return true;
207 }
208 if r.is_null() {
209 return false;
210 }
211 droid_wrap_utils::vm_attach!(mut env);
212 env.call_method(
213 r.clone(),
214 "equals",
215 "(Ljava/lang/Object;)Z",
216 &[t.as_obj().into()]
217 ).unwrap().z().unwrap()
218 }
219 }
220
221 impl #generics ToString for #name #generics {
222 fn to_string(&self) -> String {
223 let r = self.java_ref();
224 if r.is_null() {
225 return "null".to_string();
226 }
227 droid_wrap_utils::vm_attach!(mut env);
228 let s = match env.call_method(r.clone(), "toString", format!("()L{};", String::CLASS).as_str(), &[]) {
229 Ok(s) => match s.l() {
230 Ok(s) => s,
231 Err(e) => return e.to_string()
232 },
233 Err(e) => return e.to_string()
234 };
235 let s = match env.get_string((&s).into()) {
236 Ok(s) => s,
237 Err(e) => return e.to_string()
238 };
239 s.to_str().unwrap().to_string()
240 }
241 }
242
243 impl #generics std::fmt::Debug for #name #generics {
244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 write!(f, "{}", self.to_string())
246 }
247 }
248
249 impl #generics From<&droid_wrap_utils::GlobalRef> for #name #generics {
250 fn from(obj: &droid_wrap_utils::GlobalRef) -> Self {
251 Self::_new(&obj, <Self as JObjNew>::Fields::default())
252 }
253 }
254
255 impl #generics Into<droid_wrap_utils::GlobalRef> for &#name #generics {
256 fn into(self) -> droid_wrap_utils::GlobalRef {
257 self.java_ref()
258 }
259 }
260
261 #impl_based_deref
262 };
263 stream.into()
264}
265
266#[proc_macro_attribute]
286pub fn java_method(attrs: TokenStream, input: TokenStream) -> TokenStream {
287 let attrs: MethodMetadata = parse2(Into::<TokenStream2>::into(attrs)).unwrap();
288 let type_bounds = attrs.type_bounds;
289 let overload = attrs.overload;
290 let item = parse_macro_input!(input as ItemFn);
291 let attrs = item.attrs.clone();
292 let stmts = item.block.stmts.clone();
293 let name = if overload.is_none() {
294 item.sig.ident.to_string()
295 } else {
296 overload.unwrap().to_token_stream().to_string()
297 }
298 .to_lower_camel_case();
299 let vis = item.vis.clone();
300 let sig = item.sig.clone();
301
302 let (self_, _, arg_types_sig, fmt, arg_values, ret_type) =
303 parse_function_signature(&sig, &type_bounds);
304 let (ret_value, ret_type_sig, is_result_type) =
305 get_return_value_token(&ret_type, &sig.generics, &type_bounds, &None);
306
307 let ret_value = get_result_token(is_result_type, &ret_value);
308
309 let class_token = if let Some(it) = type_bounds.iter().find(|i| i.0.to_string() == "Self") {
310 let tt = it.1.clone();
311 quote! {<Self as #tt>::CLASS}
312 } else {
313 quote! {Self::CLASS}
314 };
315
316 if self_.is_none() {
317 quote! {
318 #(#attrs)*
319 #vis #sig {
320 #(#stmts)*
321 droid_wrap_utils::vm_attach!(mut env);
322 let ret = env.call_static_method(
323 #class_token,
324 #name,
325 format!(#fmt, #arg_types_sig #ret_type_sig).as_str(),
326 &[#arg_values],
327 );
328 #ret_value
329 }
330 }
331 } else {
332 quote! {
333 #(#attrs)*
334 #vis #sig {
335 #(#stmts)*
336 droid_wrap_utils::vm_attach!(mut env);
337 let ret = env.call_method(
338 #self_.java_ref(),
339 #name,
340 format!(#fmt, #arg_types_sig #ret_type_sig).as_str(),
341 &[#arg_values],
342 );
343 #ret_value
344 }
345 }
346 }
347 .into()
348}
349
350#[proc_macro_attribute]
370pub fn java_constructor(_: TokenStream, input: TokenStream) -> TokenStream {
371 let item = parse_macro_input!(input as ItemFn);
372 let attrs = item.attrs.clone();
373 let vis = item.vis.clone();
374 let sig = item.sig.clone();
375 let stmts = item.block.stmts.clone();
376 let (self_, _, arg_types, fmt, arg_values, ret_type) = parse_function_signature(&sig, &vec![]);
377
378 if !self_.is_none() {
379 panic!(
380 "Incorrect constructor, please remove the '{}' in the arguments!",
381 self_.to_token_stream()
382 );
383 }
384
385 if !ret_type.to_string().contains("Self") {
386 panic!(
387 "Incorrect constructor, please modify the '{}' to 'Self', 'Option<Self>' or 'Result<Self, Self::Error>' in the return value!",
388 ret_type
389 );
390 }
391
392 let (ret_value, _) = get_object_return_value_token(&ret_type);
393
394 let stream = quote! {
395 #(#attrs)*
396 #vis #sig {
397 #(#stmts)*
398 droid_wrap_utils::vm_attach!(mut env);
399 let obj = env.new_object(
400 <Self as JType>::CLASS,
401 format!(#fmt, #arg_types "V").as_str(),
402 &[#arg_values],
403 )
404 .unwrap();
405 #ret_value
406 }
407 };
408
409 stream.into()
410}
411
412#[proc_macro_attribute]
430pub fn java_interface(attrs: TokenStream, input: TokenStream) -> TokenStream {
431 let attrs: InterfaceMetadata = parse2(Into::<TokenStream2>::into(attrs)).unwrap();
432 let cls = attrs.interface_name;
433 let mut item = parse_macro_input!(input as ItemTrait);
434 item.supertraits
435 .push(TypeParamBound::Verbatim(quote! {JObjRef}));
436 item.supertraits
437 .push(TypeParamBound::Verbatim(quote! {JObjNew}));
438 item.supertraits
439 .push(TypeParamBound::Verbatim(quote! {PartialEq}));
440 item.supertraits
441 .push(TypeParamBound::Verbatim(quote! {std::fmt::Debug}));
442
443 item.items.push(TraitItem::Verbatim(quote! {
444 #[doc = #cls]
445 const CLASS: &'static str = #cls;
446 }));
447 item.items.push(TraitItem::Verbatim(quote! {
448 #[doc = concat!("L", #cls, ";")]
449 const OBJECT_SIG: &'static str = concat!("L", #cls, ";");
450 }));
451 item.items.push(TraitItem::Verbatim(quote! {
452 const DIM: u8 = 0;
454 }));
455 let stream = quote! {
456 #item
457 };
458 stream.into()
459}
460
461#[proc_macro_attribute]
500pub fn java_implement(attrs: TokenStream, input: TokenStream) -> TokenStream {
501 let item: TokenStream2 = input.into();
502 let attrs: TokenStream2 = attrs.into();
503
504 let item = parse2::<ItemImpl>(item.clone()).unwrap();
505
506 let mut methods = TokenStream2::new();
507 for item in item.items.iter() {
508 match item {
509 ImplItem::Fn(f) => {
510 let name = f.sig.ident.clone();
511 if name.to_string().starts_with("_") {
512 continue;
514 }
515 let name_camel = f.sig.ident.to_string().to_lower_camel_case();
516 let (self_, arg_types, _, _, _, ret_type) =
517 parse_function_signature(&f.sig, &vec![]);
518 if self_.is_none() {
519 continue;
520 }
521
522 let ret_token = match ret_type.to_string().as_str() {
523 "()" => quote! {droid_wrap_utils::null_value(env)},
524 "bool" => quote! {droid_wrap_utils::wrapper_bool_value(ret, env)},
525 "i32" => quote! {droid_wrap_utils::wrapper_integer_value(ret, env)},
526 "u32" => quote! {droid_wrap_utils::wrapper_integer_value(ret as u32, env)},
527 "i64" => quote! {droid_wrap_utils::wrapper_long_value(ret, env)},
528 "u64" => quote! {droid_wrap_utils::wrapper_long_value(ret as u64, env)},
529 _ => quote! {ret.java_ref()},
530 };
531
532 let mut arg_tokens = TokenStream2::new();
533 for i in 0..arg_types.len() {
534 let (unwrapped_ty, origin_ty) = &arg_types[i];
535 let ty_str = unwrapped_ty.to_string();
536 let ar = if [
537 "bool", "char", "i16", "u16", "i32", "u32", "i64", "u64", "f32", "f64",
538 ]
539 .contains(&ty_str.as_str())
540 {
541 quote! {
542 droid_wrap_utils::ParseJObjectType::<#unwrapped_ty>::parse(&args2[#i], env),
543 }
544 } else if origin_ty.to_string().starts_with("Option") {
545 quote! {{
546 if args2[#i].is_null() {
547 None
548 } else {
549 let r = env.new_global_ref(&args2[#i]).unwrap();
550 Some(#unwrapped_ty::_new(&r, Default::default()))
551 }
552 },}
553 } else {
554 quote! {{
555 let r = env.new_global_ref(&args2[#i]).unwrap();
556 #unwrapped_ty::_new(&r, Default::default())
557 },}
558 };
559 arg_tokens.extend(ar);
560 }
561 methods.extend(quote! {
562 Ok(#name_camel) => {
563 let args2 = droid_wrap_utils::to_vec(env, &args);
564 let ret = self_.#name(#arg_tokens);
565 #ret_token
566 },
567 })
568 }
569 _ => {}
570 }
571 }
572 let name = item.self_ty.clone();
575 let class_token = match item.trait_ {
576 None => quote! {Self::CLASS},
577 Some((_, ref p, _)) => quote! {<Self as #p>::CLASS},
578 };
579
580 let impl_new = quote! {
581 fn new(fields: Self::Fields) -> std::sync::Arc<Self> {
582 use std::sync::Arc;
583 let interface = #class_token.replace("/", ".");
584 let proxy = droid_wrap_utils::new_proxy(&[&interface]);
585 let ret = Arc::new(Self::_new(&proxy, fields));
586 let self_ = ret.clone();
587 droid_wrap_utils::bind_proxy_handler(&proxy, move |env, method, args| {
588 let name = env.call_method(&method, "getName", "()Ljava/lang/String;", &[]).unwrap().l().unwrap();
589 let name = env.get_string((&name).into()).unwrap();
590 match name.to_str() {
591 #methods
592 _ => droid_wrap_utils::null_value(env)
593 }
594 });
595 ret
596 }
597 };
598
599 let stream = quote! {
600 #attrs
601 #item
602
603 impl JProxy for #name {
604 #impl_new
605 }
606
607 impl Drop for #name {
608 fn drop(&mut self) {
609 self.release();
610 }
611 }
612 };
613
614 stream.into()
615}
616
617#[proc_macro_attribute]
642pub fn java_field(attrs: TokenStream, input: TokenStream) -> TokenStream {
643 let attrs: FieldMetadata = parse2(Into::<TokenStream2>::into(attrs)).unwrap();
644 let default_value = attrs.default_value.clone();
645 let item = parse_macro_input!(input as ItemFn);
646 let attrs = item.attrs.clone();
647 let stmts = item.block.stmts.clone();
648 let name = item.sig.ident.to_string().to_lower_camel_case();
649 let vis = item.vis.clone();
650 let sig = item.sig.clone();
651
652 let (is_set, name) = if name.starts_with("get") {
653 (false, name.trim_start_matches("get").to_lower_camel_case())
654 } else if name.starts_with("set") {
655 (true, name.trim_start_matches("set").to_lower_camel_case())
656 } else {
657 panic!("Field name `{}` must start with get or set.", name);
658 };
659
660 let (self_, arg_types, arg_types_sig, _, arg_values, ret_type) =
661 parse_function_signature(&sig, &vec![]);
662 if is_set {
663 if arg_types.len() != 1 {
664 panic!(
665 "The number of setter arguments for the field `{}` must be one.",
666 name
667 )
668 }
669 } else {
670 if !arg_types.is_empty() {
671 panic!("The getter field `{}` cannot provide any arguments.", name)
672 }
673 }
674
675 let (ret_value, ret_type_sig, is_result_type) =
676 get_return_value_token(&ret_type, &sig.generics, &vec![], &default_value);
677
678 let ret_value = get_result_token(is_result_type, &ret_value);
679
680 let opt = if is_set {
681 if self_.is_none() {
682 quote! {
683 let ret = env.set_static_field(Self::CLASS, #name, #arg_types_sig #arg_values);
684 }
685 } else {
686 quote! {
687 let ret = env.set_field(#self_.java_ref(), #name, #arg_types_sig #arg_values);
688 }
689 }
690 } else {
691 if self_.is_none() {
692 quote! {
693 let ret = env.get_static_field(Self::CLASS, #name, #ret_type_sig);
694 }
695 } else {
696 quote! {
697 let ret = env.get_field(#self_.java_ref(), #name, #ret_type_sig);
698 }
699 }
700 };
701 let stream = quote! {
702 #(#attrs)*
703 #vis #sig {
704 #(#stmts)*
705 droid_wrap_utils::vm_attach!(mut env);
706 #opt
707 #ret_value
708 }
709 };
710 stream.into()
711}