1use crate::{
2 argument::DuchessDeclaration,
3 class_info::{
4 ClassInfo, Constructor, DotId, Field, Id, Method, NonRepeatingType, RootMap,
5 SpannedPackageInfo, Type,
6 },
7 reflect::Reflector,
8 signature::Signature,
9 upcasts::Upcasts,
10};
11use inflector::Inflector;
12use proc_macro2::{Ident, Literal, Span, TokenStream};
13use quote::quote_spanned;
14
15impl DuchessDeclaration {
16 pub fn to_tokens(&self) -> syn::Result<TokenStream> {
17 let reflector = &mut Reflector::default();
18 let root_map = self.to_root_map(reflector)?;
19 let () = root_map.check(reflector)?;
20 root_map.to_tokens(reflector)
21 }
22}
23
24impl RootMap {
25 fn to_tokens(self, reflector: &mut Reflector) -> syn::Result<TokenStream> {
26 self.to_packages()
27 .map(|p| p.to_tokens(&[], &self, reflector))
28 .collect()
29 }
30}
31
32impl SpannedPackageInfo {
33 fn to_tokens(
34 &self,
35 parents: &[Id],
36 root_map: &RootMap,
37 reflector: &mut Reflector,
38 ) -> syn::Result<TokenStream> {
39 let package_id = DotId::new(parents, &self.name);
40 let name = self.name.to_ident(self.span);
41
42 let subpackage_tokens: TokenStream = self
43 .subpackages
44 .values()
45 .map(|p| p.to_tokens(&package_id, root_map, reflector))
46 .collect::<Result<_, _>>()?;
47
48 let class_tokens: TokenStream = self
49 .classes
50 .iter()
51 .map(|class_id| root_map.classes[class_id].to_tokens(&root_map.upcasts))
52 .collect::<Result<_, _>>()?;
53
54 let supers: Vec<TokenStream> = package_id
55 .iter()
56 .map(|_| quote_spanned!(self.span => super))
57 .collect();
58
59 Ok(quote_spanned!(self.span =>
60 #[allow(unused_imports)]
61 pub mod #name {
62 use #(#supers ::)* *;
64
65 use duchess::java;
67
68 #subpackage_tokens
69 #class_tokens
70 }
71 ))
72 }
73}
74
75impl ClassInfo {
76 pub fn to_tokens(&self, upcasts: &Upcasts) -> syn::Result<TokenStream> {
77 let struct_name = self.struct_name();
78 let cached_class = self.cached_class();
79 let this_ty = self.this_type();
80 let java_class_generics_with_defaults = self.class_generic_names_with_defaults();
81 let java_class_generics = self.class_generic_names();
82
83 let constructors: Vec<_> = self
85 .constructors
86 .iter()
87 .map(|c| self.constructor(c))
88 .collect::<Result<_, _>>()?;
89
90 let static_methods: Vec<_> = self
92 .methods
93 .iter()
94 .filter(|m| self.should_mirror_in_rust(m.flags.privacy))
95 .filter(|m| m.flags.is_static)
96 .map(|m| self.static_method(m))
97 .collect::<Result<_, _>>()?;
98
99 let op_methods: Vec<_> = self
101 .methods
102 .iter()
103 .filter(|m| self.should_mirror_in_rust(m.flags.privacy))
104 .filter(|m| !m.flags.is_static)
105 .map(|m| self.op_struct_method(m))
106 .collect::<Result<_, _>>()?;
107
108 let obj_methods: Vec<_> = self
110 .methods
111 .iter()
112 .filter(|m| self.should_mirror_in_rust(m.flags.privacy))
113 .filter(|m| !m.flags.is_static)
114 .map(|m| self.obj_struct_method(m))
115 .collect::<Result<_, _>>()?;
116
117 let assoc_struct_declarations = self.assoc_structs(upcasts, op_methods, obj_methods)?;
118
119 let inherent_object_methods: Vec<_> = self
121 .methods
122 .iter()
123 .filter(|m| self.should_mirror_in_rust(m.flags.privacy))
124 .filter(|m| !m.flags.is_static)
125 .map(|m| self.inherent_object_method(m))
126 .collect::<Result<_, _>>()?;
127
128 let static_field_getters: Vec<_> = self
130 .fields
131 .iter()
132 .filter(|f: &&Field| self.should_mirror_in_rust(f.flags.privacy))
133 .filter(|f| f.flags.is_static)
134 .map(|f| self.static_field_getter(f))
135 .collect::<Result<_, _>>()?;
136
137 let upcast_impls = self.upcast_impls(upcasts)?;
138
139 let output = quote_spanned! {
140 self.span =>
141
142 #[allow(non_camel_case_types)]
143 pub struct #struct_name<#(#java_class_generics_with_defaults,)*> {
144 _empty: std::convert::Infallible,
145 _dummy: ::core::marker::PhantomData<(#(#java_class_generics,)*)>
146 }
147
148 #[allow(unused_imports)]
150 #[allow(nonstandard_style)]
151 const _: () = {
152 #assoc_struct_declarations
153
154 unsafe impl<#(#java_class_generics,)*> duchess::JavaObject for #struct_name<#(#java_class_generics,)*>
155 where
156 #(#java_class_generics: duchess::JavaObject,)*
157 {
158 #cached_class
159 }
160
161 impl<#(#java_class_generics,)*> ::core::convert::AsRef<#struct_name<#(#java_class_generics,)*>> for #struct_name<#(#java_class_generics,)*>
162 where
163 #(#java_class_generics: duchess::JavaObject,)*
164 {
165 fn as_ref(&self) -> &#struct_name<#(#java_class_generics,)*> {
166 self
167 }
168 }
169
170 impl<#(#java_class_generics,)*> ::core::ops::Deref for #struct_name<#(#java_class_generics,)*>
171 where
172 #(#java_class_generics: duchess::JavaObject,)*
173 {
174 type Target = <Self as duchess::plumbing::JavaView>::OfObj<Self>;
175
176 fn deref(&self) -> &Self::Target {
177 duchess::plumbing::FromRef::from_ref(self)
178 }
179 }
180
181 impl<#(#java_class_generics,)*> duchess::prelude::JDeref for #struct_name<#(#java_class_generics,)*>
182 where
183 #(#java_class_generics: duchess::JavaObject,)*
184 {
185 fn jderef(&self) -> &Self {
186 self
187 }
188 }
189
190 impl<#(#java_class_generics,)*> duchess::prelude::TryJDeref for #struct_name<#(#java_class_generics,)*>
191 where
192 #(#java_class_generics: duchess::JavaObject,)*
193 {
194 type Java = Self;
195
196 fn try_jderef(&self) -> duchess::Nullable<&Self> {
197 Ok(self)
198 }
199 }
200
201 unsafe impl<#(#java_class_generics,)*> duchess::plumbing::Upcast<#struct_name<#(#java_class_generics,)*>> for #struct_name<#(#java_class_generics,)*>
203 where
204 #(#java_class_generics: duchess::JavaObject,)*
205 {}
206
207 #upcast_impls
209
210 impl< #(#java_class_generics,)* > #this_ty
211 where
212 #(#java_class_generics: duchess::JavaObject,)*
213 {
214 #(#constructors)*
215
216 #(#static_methods)*
217
218 #(#static_field_getters)*
219
220 #(#inherent_object_methods)*
221 }
222 };
223 };
224
225 crate::debug_tokens(&self.name, &output);
226
227 Ok(output)
228 }
229
230 fn assoc_structs(
233 &self,
234 upcasts: &Upcasts,
235 op_struct_methods: Vec<TokenStream>,
236 obj_struct_methods: Vec<TokenStream>,
237 ) -> syn::Result<TokenStream> {
238 let name = self.struct_name();
239 let java_class_generics = self.class_generic_names();
240
241 let j = Ident::new("J", self.span);
246 let n = Ident::new("N", self.span);
247
248 let struct_definition = |struct_name: &Ident| {
253 quote_spanned!(self.span =>
254 #[repr(transparent)]
255 pub struct #struct_name<#(#java_class_generics,)* #j, #n> {
256 this: #j,
257 phantom: ::core::marker::PhantomData<(#name<#(#java_class_generics),*>, #n)>,
258 }
259 )
260 };
261
262 let deref_impl = |struct_name: &Ident| {
263 quote_spanned!(self.span =>
264 impl<#(#java_class_generics,)* #j, #n> ::core::ops::Deref
265 for #struct_name<#(#java_class_generics,)* #j, #n>
266 where
267 #n: duchess::plumbing::FromRef<#j>,
268 {
269 type Target = #n;
270
271 fn deref(&self) -> &#n {
272 duchess::plumbing::FromRef::from_ref(&self.this)
273 }
274 }
275 )
276 };
277
278 let from_ref_impl = |struct_name: &Ident| {
279 quote_spanned!(self.span =>
280 impl<#(#java_class_generics,)* #j, #n> duchess::plumbing::FromRef<#j> for #struct_name<#(#java_class_generics,)* #j, #n> {
281 fn from_ref(j: &J) -> &Self {
282 unsafe {
285 ::core::mem::transmute::<&J, &Self>(j)
286 }
287 }
288 }
289 )
290 };
291
292 let mro = self.mro(upcasts)?;
294
295 let op_name = Id::from(format!("ViewAs{}Op", self.name.class_name())).to_ident(self.span);
296 let op_mro_tokens = self.mro_tokens(&j, "OfOpWith", &mro);
297
298 let obj_name = Id::from(format!("ViewAs{}Obj", self.name.class_name())).to_ident(self.span);
299 let obj_mro_tokens = self.mro_tokens(&j, "OfObjWith", &mro);
300
301 let all_names = &[&op_name, &obj_name];
302
303 let this_ty = self.this_type();
304
305 let other_impls = quote_spanned!(self.span =>
306 impl<#(#java_class_generics,)*> duchess::plumbing::JavaView for #name<#(#java_class_generics,)*>
307 {
308 type OfOp<#j> = #op_name<#(#java_class_generics,)* #j, #op_mro_tokens>;
309
310 type OfOpWith<#j, #n> = #op_name<#(#java_class_generics,)* #j, #n>
311 where
312 N: duchess::plumbing::FromRef<J>;
313
314 type OfObj<#j> = #obj_name<#(#java_class_generics,)* #j, #obj_mro_tokens>;
315
316 type OfObjWith<#j, #n> = #obj_name<#(#java_class_generics,)* #j, #n>
317 where
318 N: duchess::plumbing::FromRef<J>;
319 }
320
321 impl<#(#java_class_generics,)* #j, #n> #op_name<#(#java_class_generics,)* #j, #n>
322 where
323 #(#java_class_generics: duchess::JavaObject,)*
324 #j: duchess::plumbing::JvmRefOp<#name<#(#java_class_generics,)*>>,
325 #n: duchess::plumbing::FromRef<#j>,
326 {
327 #(#op_struct_methods)*
328 }
329
330 impl<#(#java_class_generics,)* #j, #n> #obj_name<#(#java_class_generics,)* #j, #n>
331 where
332 #(#java_class_generics: duchess::JavaObject,)*
333 for<'jvm> &'jvm #j: duchess::plumbing::JvmRefOp<#this_ty>,
334 {
335 #(#obj_struct_methods)*
336 }
337 );
338
339 let declarations: TokenStream = all_names
340 .iter()
341 .copied()
342 .flat_map(|n| vec![struct_definition(n), deref_impl(n), from_ref_impl(n)])
343 .chain(Some(other_impls))
344 .collect();
345
346 Ok(declarations)
347 }
348
349 fn mro_tokens(&self, j: &Ident, assoc_name: &str, mro: &[TokenStream]) -> TokenStream {
357 let Some((head, tail)) = mro.split_first() else {
358 return quote_spanned!(self.span => ());
359 };
360
361 let tail_tokens = self.mro_tokens(j, assoc_name, tail);
362
363 let assoc_ident = Ident::new(assoc_name, self.span);
364 quote_spanned!(self.span =>
365 <#head as duchess::plumbing::JavaView>::#assoc_ident<#j, #tail_tokens>
366 )
367 }
368
369 fn mro(&self, upcasts: &Upcasts) -> syn::Result<Vec<TokenStream>> {
381 let class_refs = upcasts.upcasts_for_generated_class(&self.name);
382 class_refs
383 .iter()
384 .map(|r| {
385 let mut sig = Signature::new(&Id::from("supertrait"), self.span, &[])
386 .with_internal_generics(&self.generics)?;
387 Ok(sig.forbid_capture(|sig| sig.class_ref_ty(r)).unwrap())
388 })
389 .collect()
390 }
391
392 fn upcast_impls(&self, upcasts: &Upcasts) -> syn::Result<TokenStream> {
393 let struct_name = self.struct_name();
394 let java_class_generics = self.class_generic_names();
395 Ok(self.mro(upcasts)?
396 .into_iter()
397 .map(|tokens| {
398 quote_spanned!(self.span =>
399 unsafe impl<#(#java_class_generics,)*> duchess::plumbing::Upcast<#tokens> for #struct_name<#(#java_class_generics,)*>
400 where
401 #(#java_class_generics: duchess::JavaObject,)*
402 {}
403 )
404 })
405 .collect())
406 }
407
408 fn cached_class(&self) -> TokenStream {
409 let jni_class_name = self.jni_class_name();
410
411 quote_spanned! {
412 self.span =>
413 fn class<'jvm>(jvm: &mut duchess::Jvm<'jvm>) -> duchess::LocalResult<'jvm, duchess::Local<'jvm, java::lang::Class>> {
414 static CLASS: duchess::plumbing::once_cell::sync::OnceCell<duchess::Java<java::lang::Class>> = duchess::plumbing::once_cell::sync::OnceCell::new();
415 let global = CLASS.get_or_try_init::<_, duchess::Error<duchess::Local<java::lang::Throwable>>>(|| {
416 let class = duchess::plumbing::find_class(jvm, #jni_class_name)?;
417 Ok(jvm.global(&class))
418 })?;
419 Ok(jvm.local(global))
420 }
421 }
422 }
423
424 fn constructor(&self, constructor: &Constructor) -> syn::Result<TokenStream> {
425 let mut sig = Signature::new(self.name.class_name(), self.span, &self.generics);
426
427 let (input_traits, jvm_op_traits): (Vec<_>, Vec<_>) = constructor
428 .argument_tys
429 .iter()
430 .map(|ty| sig.input_and_jvm_op_traits(ty))
431 .collect::<Result<Vec<_>, _>>()?
432 .into_iter()
433 .unzip();
434
435 let input_names: Vec<_> = (0..input_traits.len())
436 .map(|i| Ident::new(&format!("a{i}"), self.span))
437 .collect();
438
439 let ty = self.this_type();
440 let output_trait = quote_spanned!(self.span => duchess::prelude::JavaConstructor<#ty>);
441
442 let java_class_generics = self.class_generic_names();
443
444 let jni_descriptor = jni_c_str(constructor.descriptor(&self.generics_scope()), self.span);
445
446 let prepare_inputs = self.prepare_inputs(&input_names, &constructor.argument_tys);
448
449 let name = Literal::string(&self.name.to_string());
451 let descriptor = Literal::string(&constructor.descriptor(&self.generics_scope()));
452
453 let output = quote_spanned!(self.span =>
454 pub fn new(
455 #(#input_names : impl #input_traits,)*
456 ) -> impl #output_trait {
457 struct Impl<
458 #(#java_class_generics,)*
459 #(#input_names),*
460 > {
461 #(#input_names: #input_names,)*
462 phantom: ::core::marker::PhantomData<(
463 #(#java_class_generics,)*
464 )>,
465 }
466
467 impl<
468 #(#java_class_generics,)*
469 #(#input_names,)*
470 > ::core::clone::Clone for Impl<
471 #(#java_class_generics,)*
472 #(#input_names,)*
473 >
474 where
475 #(#java_class_generics: duchess::JavaObject,)*
476 #(#input_names : #jvm_op_traits,)*
477 {
478 fn clone(&self) -> Self {
479 Impl {
480 #(#input_names: Clone::clone(&self.#input_names),)*
481 phantom: self.phantom,
482 }
483 }
484 }
485
486 impl<
487 #(#java_class_generics,)*
488 #(#input_names,)*
489 > duchess::prelude::JvmOp for Impl<
490 #(#java_class_generics,)*
491 #(#input_names,)*
492 >
493 where
494 #(#java_class_generics: duchess::JavaObject,)*
495 #(#input_names : #jvm_op_traits,)*
496 {
497 type Output<'jvm> = duchess::Local<'jvm, #ty>;
498
499 fn do_jni<'jvm>(
500 self,
501 jvm: &mut duchess::Jvm<'jvm>,
502 ) -> duchess::LocalResult<'jvm, Self::Output<'jvm>> {
503 #(#prepare_inputs)*
504
505 let class = <#ty as duchess::JavaObject>::class(jvm)?;
506
507 static CONSTRUCTOR: duchess::plumbing::once_cell::sync::OnceCell<duchess::plumbing::MethodPtr> = duchess::plumbing::once_cell::sync::OnceCell::new();
511 let constructor = CONSTRUCTOR.get_or_try_init(|| {
512 duchess::plumbing::find_constructor(jvm, &class, #jni_descriptor)
513 })?;
514
515 let env = jvm.env();
516 let obj: ::core::option::Option<duchess::Local<#ty>> = unsafe {
517 env.invoke(|env| env.NewObjectA, |env, f| f(
518 env,
519 duchess::plumbing::JavaObjectExt::as_raw(&*class).as_ptr(),
520 constructor.as_ptr(),
521 [
522 #(duchess::plumbing::IntoJniValue::into_jni_value(#input_names),)*
523 ].as_ptr(),
524 ))
525 }?;
526 obj.ok_or_else(|| {
527 duchess::Error::JvmInternal(format!(
530 "failed to create new `{}` via constructor `{}`",
531 #name, #descriptor,
532 ))
533 })
534 }
535 }
536
537 impl<
538 #(#java_class_generics,)*
539 #(#input_names,)*
540 > ::core::ops::Deref for Impl<
541 #(#java_class_generics,)*
542 #(#input_names,)*
543 > {
544 type Target = <#ty as duchess::plumbing::JavaView>::OfOp<Self>;
545
546 fn deref(&self) -> &Self::Target {
547 <Self::Target as duchess::plumbing::FromRef<_>>::from_ref(self)
548 }
549 }
550
551 Impl {
552 #(#input_names: #input_names.into_op(),)*
553 phantom: ::core::default::Default::default()
554 }
555 }
556 );
557
558 Ok(output)
562 }
563
564 fn op_struct_method(&self, method: &Method) -> syn::Result<TokenStream> {
570 let mut sig = Signature::new(&method.name, self.span, &self.generics)
571 .with_internal_generics(&method.generics)?;
572
573 let (input_traits, _jvm_op_traits): (Vec<_>, Vec<_>) = method
574 .argument_tys
575 .iter()
576 .map(|ty| sig.input_and_jvm_op_traits(ty))
577 .collect::<Result<Vec<_>, _>>()?
578 .into_iter()
579 .unzip();
580
581 let input_names: Vec<_> = (0..input_traits.len())
582 .map(|i| Ident::new(&format!("a{i}"), self.span))
583 .collect();
584
585 let output_trait = sig.method_trait(&method.return_ty)?;
590
591 let rust_method_name = Id::from(method.name.to_snake_case()).to_ident(self.span);
592
593 let rust_method_generics = &sig.rust_generics;
598
599 let sig_where_clauses = &sig.where_clauses;
604
605 let this_ty = self.this_type();
606
607 let inherent_method = quote_spanned!(self.span =>
608 pub fn #rust_method_name<#(#rust_method_generics),*>(
609 &self,
610 #(#input_names: impl #input_traits),*
611 ) -> impl #output_trait
612 where
613 #(#sig_where_clauses,)*
614 {
615 <#this_ty>::#rust_method_name(
616 Clone::clone(&self.this),
617 #(#input_names,)*
618 )
619 }
620 );
621
622 Ok(inherent_method)
623 }
624
625 fn obj_struct_method(&self, method: &Method) -> syn::Result<TokenStream> {
626 let mut sig = Signature::new(&method.name, self.span, &self.generics)
627 .with_internal_generics(&method.generics)?;
628
629 let (input_traits, _jvm_op_traits): (Vec<_>, Vec<_>) = method
630 .argument_tys
631 .iter()
632 .map(|ty| sig.input_and_jvm_op_traits(ty))
633 .collect::<Result<Vec<_>, _>>()?
634 .into_iter()
635 .unzip();
636
637 let input_names: Vec<_> = (0..input_traits.len())
638 .map(|i| Ident::new(&format!("a{i}"), self.span))
639 .collect();
640
641 let output_trait = sig.method_trait(&method.return_ty)?;
646
647 let rust_method_name = Id::from(method.name.to_snake_case()).to_ident(self.span);
648
649 let rust_method_generics = &sig.rust_generics;
654
655 let sig_where_clauses = &sig.where_clauses;
660
661 let this_ty = self.this_type();
662
663 let inherent_method = quote_spanned!(self.span =>
664 pub fn #rust_method_name<'a, #(#rust_method_generics),*>(
665 &'a self,
666 #(#input_names: impl #input_traits + 'a),*
667 ) -> impl #output_trait + 'a
668 where
669 #(#sig_where_clauses,)*
670 {
671 <#this_ty>::#rust_method_name(
672 &self.this,
673 #(#input_names,)*
674 )
675 }
676 );
677
678 Ok(inherent_method)
679 }
680
681 fn inherent_object_method(&self, method: &Method) -> syn::Result<TokenStream> {
682 let mut sig = Signature::new(&method.name, self.span, &self.generics)
683 .with_internal_generics(&method.generics)?;
684
685 let (input_traits, jvm_op_traits): (Vec<_>, Vec<_>) = method
686 .argument_tys
687 .iter()
688 .map(|ty| sig.input_and_jvm_op_traits(ty))
689 .collect::<Result<Vec<_>, _>>()?
690 .into_iter()
691 .unzip();
692
693 let input_names: Vec<_> = (0..input_traits.len())
694 .map(|i| Ident::new(&format!("a{i}"), self.span))
695 .collect();
696
697 let output_ty = sig.output_type(&method.return_ty)?;
700
701 let output_trait = sig.method_trait(&method.return_ty)?;
706
707 let jni_call_fn = sig.jni_call_fn(&method.return_ty)?;
709
710 let java_ref_output_ty = match &method.return_ty {
714 Some(java_return_type) => {
715 sig.forbid_capture(|sig| sig.java_ty_if_ref(java_return_type))?
716 }
717 None => None,
718 };
719
720 let jni_descriptor = jni_c_str(&method.descriptor(&self.generics_scope()), self.span);
721
722 let prepare_inputs = self.prepare_inputs(&input_names, &method.argument_tys);
724
725 let jni_method = jni_c_str(&*method.name, self.span);
726
727 let rust_method_name = Id::from(method.name.to_snake_case()).to_ident(self.span);
728 let rust_method_type_name = Id::from(method.name.to_camel_case()).to_ident(self.span);
729
730 let java_class_generics: Vec<_> = self.class_generic_names();
732
733 let rust_method_generics = &sig.rust_generics;
738
739 let this = Ident::new("this", self.span);
743 let method_struct_generics: Vec<_> = java_class_generics
744 .iter()
745 .chain(rust_method_generics)
746 .chain(Some(&this))
747 .chain(&input_names)
748 .collect();
749
750 let method_struct = quote_spanned!(self.span =>
753 pub struct #rust_method_type_name<
754 #(#method_struct_generics,)*
755 > {
756 #this: #this,
757 #(#input_names : #input_names,)*
758 phantom: ::core::marker::PhantomData<(
759 #(#method_struct_generics,)*
760 )>,
761 }
762 );
763
764 let sig_where_clauses = &sig.where_clauses;
769
770 let this_ty = self.this_type();
772
773 let jvmop_impl = quote_spanned!(self.span =>
776 impl<#(#method_struct_generics),*> ::core::clone::Clone
777 for #rust_method_type_name<#(#method_struct_generics),*>
778 where
779 #this: duchess::plumbing::JvmRefOp<#this_ty>,
780 #(#input_names: #jvm_op_traits,)*
781 #(#java_class_generics: duchess::JavaObject,)*
782 #(#sig_where_clauses,)*
783 {
784 fn clone(&self) -> Self {
785 #rust_method_type_name {
786 #this: Clone::clone(&self.#this),
787 #(#input_names: Clone::clone(&self.#input_names),)*
788 phantom: self.phantom,
789 }
790 }
791 }
792
793 impl<#(#method_struct_generics),*> duchess::prelude::JvmOp
794 for #rust_method_type_name<#(#method_struct_generics),*>
795 where
796 #this: duchess::plumbing::JvmRefOp<#this_ty>,
797 #(#input_names: #jvm_op_traits,)*
798 #(#java_class_generics: duchess::JavaObject,)*
799 #(#sig_where_clauses,)*
800 {
801 type Output<'jvm> = #output_ty;
802
803 fn do_jni<'jvm>(
804 self,
805 jvm: &mut duchess::Jvm<'jvm>,
806 ) -> duchess::LocalResult<'jvm, Self::Output<'jvm>> {
807 let this = self.#this.into_as_jref(jvm)?;
808 let this: & #this_ty = duchess::prelude::AsJRef::as_jref(&this)?;
809 let this = duchess::plumbing::JavaObjectExt::as_raw(this);
810
811 #(#prepare_inputs)*
812
813 static METHOD: duchess::plumbing::once_cell::sync::OnceCell<duchess::plumbing::MethodPtr> = duchess::plumbing::once_cell::sync::OnceCell::new();
817 let method = METHOD.get_or_try_init(|| {
818 let class = <#this_ty as duchess::JavaObject>::class(jvm)?;
819 duchess::plumbing::find_method(jvm, &class, #jni_method, #jni_descriptor, false)
820 })?;
821
822 unsafe {
823 jvm.env().invoke(|env| env.#jni_call_fn, |env, f| f(
824 env,
825 this.as_ptr(),
826 method.as_ptr(),
827 [
828 #(duchess::plumbing::IntoJniValue::into_jni_value(#input_names),)*
829 ].as_ptr(),
830 ))
831 }
832 }
833 }
834 );
835
836 let deref_impl = java_ref_output_ty.map(|java_ref_output_ty| {
840 quote_spanned!(self.span =>
841 impl<#(#method_struct_generics),*> ::core::ops::Deref
842 for #rust_method_type_name<#(#method_struct_generics),*>
843 where
844 #(#java_class_generics: duchess::JavaObject,)*
845 #(#sig_where_clauses,)*
846 {
847 type Target = <#java_ref_output_ty as duchess::plumbing::JavaView>::OfOp<Self>;
848
849 fn deref(&self) -> &Self::Target {
850 <Self::Target as duchess::plumbing::FromRef<_>>::from_ref(self)
851 }
852 }
853 )
854 });
855
856 let inherent_method = quote_spanned!(self.span =>
857 pub fn #rust_method_name<#(#rust_method_generics),*>(
858 #this: impl duchess::prelude::IntoJava<#this_ty>,
859 #(#input_names: impl #input_traits),*
860 ) -> impl #output_trait
861 where
862 #(#sig_where_clauses,)*
863 {
864 #method_struct
865
866 #jvmop_impl
867
868 #deref_impl
869
870 #rust_method_type_name {
871 #this: #this.into_op(),
872 #(#input_names: #input_names.into_op(),)*
873 phantom: ::core::default::Default::default(),
874 }
875 }
876 );
877
878 Ok(inherent_method)
879 }
880
881 fn static_method(&self, method: &Method) -> syn::Result<TokenStream> {
887 assert!(method.flags.is_static);
888
889 let mut sig = Signature::new(&method.name, self.span, &self.generics)
890 .with_internal_generics(&method.generics)?;
891
892 let (input_traits, jvm_op_traits): (Vec<_>, Vec<_>) = method
893 .argument_tys
894 .iter()
895 .map(|ty| sig.input_and_jvm_op_traits(ty))
896 .collect::<Result<Vec<_>, _>>()?
897 .into_iter()
898 .unzip();
899
900 let input_names: Vec<_> = (0..input_traits.len())
901 .map(|i| Ident::new(&format!("a{i}"), self.span))
902 .collect();
903
904 let output_ty = sig.output_type(&method.return_ty)?;
905 let output_trait = sig.method_trait(&method.return_ty)?;
906 let jni_call_fn = sig.jni_static_call_fn(&method.return_ty)?;
907
908 let java_ref_output_ty = match &method.return_ty {
912 Some(java_return_type) => {
913 sig.forbid_capture(|sig| sig.java_ty_if_ref(java_return_type))?
914 }
915 None => None,
916 };
917
918 let jni_descriptor = jni_c_str(&method.descriptor(&self.generics_scope()), self.span);
919
920 let prepare_inputs = self.prepare_inputs(&input_names, &method.argument_tys);
922
923 let jni_method = jni_c_str(&*method.name, self.span);
924
925 let rust_method_name = Id::from(method.name.to_snake_case()).to_ident(self.span);
926 let rust_method_type_name = Id::from(method.name.to_camel_case()).to_ident(self.span);
927
928 let java_class_generics: Vec<_> = self.class_generic_names();
930
931 let rust_method_generics = &sig.rust_generics;
936
937 let method_struct_generics: Vec<_> = java_class_generics
941 .iter()
942 .chain(rust_method_generics)
943 .chain(&input_names)
944 .collect();
945
946 let method_struct = quote_spanned!(self.span =>
949 pub struct #rust_method_type_name<
950 #(#method_struct_generics,)*
951 > {
952 #(#input_names : #input_names,)*
953 phantom: ::core::marker::PhantomData<(
954 #(#method_struct_generics,)*
955 )>,
956 }
957 );
958
959 let sig_where_clauses = &sig.where_clauses;
960
961 let this_ty = self.this_type();
964 let jvmop_impl = quote_spanned!(self.span =>
965 impl<#(#method_struct_generics),*> ::core::clone::Clone
966 for #rust_method_type_name<#(#method_struct_generics),*>
967 where
968 #(#input_names: #jvm_op_traits,)*
969 #(#java_class_generics: duchess::JavaObject,)*
970 #(#sig_where_clauses,)*
971 {
972 fn clone(&self) -> Self {
973 #rust_method_type_name {
974 #(#input_names: Clone::clone(&self.#input_names),)*
975 phantom: self.phantom,
976 }
977 }
978 }
979
980 impl<#(#method_struct_generics),*> duchess::prelude::JvmOp
981 for #rust_method_type_name<#(#method_struct_generics),*>
982 where
983 #(#input_names: #jvm_op_traits,)*
984 #(#java_class_generics: duchess::JavaObject,)*
985 #(#sig_where_clauses,)*
986 {
987 type Output<'jvm> = #output_ty;
988
989 fn do_jni<'jvm>(
990 self,
991 jvm: &mut duchess::Jvm<'jvm>,
992 ) -> duchess::LocalResult<'jvm, Self::Output<'jvm>> {
993 #(#prepare_inputs)*
994
995 static METHOD: duchess::plumbing::once_cell::sync::OnceCell<duchess::plumbing::MethodPtr> = duchess::plumbing::once_cell::sync::OnceCell::new();
999 let method = METHOD.get_or_try_init(|| {
1000 let class = <#this_ty as duchess::JavaObject>::class(jvm)?;
1001 duchess::plumbing::find_method(jvm, &class, #jni_method, #jni_descriptor, true)
1002 })?;
1003
1004 let class = <#this_ty as duchess::JavaObject>::class(jvm)?;
1005 unsafe {
1006 jvm.env().invoke(|env| env.#jni_call_fn, |env, f| f(
1007 env,
1008 duchess::plumbing::JavaObjectExt::as_raw(&*class).as_ptr(),
1009 method.as_ptr(),
1010 [
1011 #(duchess::plumbing::IntoJniValue::into_jni_value(#input_names),)*
1012 ].as_ptr(),
1013 ))
1014 }
1015 }
1016 }
1017 );
1018
1019 let deref_impl = java_ref_output_ty.map(|java_ref_output_ty| {
1023 quote_spanned!(self.span =>
1024 impl<#(#method_struct_generics),*> ::core::ops::Deref
1025 for #rust_method_type_name<#(#method_struct_generics),*>
1026 where
1027 #(#java_class_generics: duchess::JavaObject,)*
1028 #(#sig_where_clauses,)*
1029 {
1030 type Target = <#java_ref_output_ty as duchess::plumbing::JavaView>::OfOp<Self>;
1031
1032 fn deref(&self) -> &Self::Target {
1033 <Self::Target as duchess::plumbing::FromRef<_>>::from_ref(self)
1034 }
1035 }
1036 )
1037 });
1038
1039 let inherent_method = quote_spanned!(self.span =>
1040 pub fn #rust_method_name<#(#rust_method_generics),*>(
1041 #(#input_names: impl #input_traits),*
1042 ) -> impl #output_trait
1043 where
1044 #(#sig_where_clauses,)*
1045 {
1046 #method_struct
1047
1048 #jvmop_impl
1049
1050 #deref_impl
1051
1052 #rust_method_type_name {
1053 #(#input_names: #input_names.into_op(),)*
1054 phantom: ::core::default::Default::default(),
1055 }
1056 }
1057 );
1058
1059 Ok(inherent_method)
1060 }
1061
1062 fn static_field_getter(&self, field: &Field) -> syn::Result<TokenStream> {
1068 assert!(field.flags.is_static);
1069
1070 let mut sig = Signature::new(&field.name, self.span, &self.generics);
1071
1072 let output_ty = sig.non_void_output_type(&field.ty)?;
1073 let output_trait = sig.field_trait(&field.ty)?;
1074 let jni_field_fn = sig.jni_static_field_get_fn(&field.ty)?;
1075
1076 let jni_field = jni_c_str(&*field.name, self.span);
1077 let jni_descriptor = jni_c_str(&field.ty.descriptor(&self.generics_scope()), self.span);
1078
1079 let rust_field_name =
1080 Id::from(format!("get_{}", field.name.to_snake_case())).to_ident(self.span);
1081 let rust_field_type_name =
1082 Id::from(format!("{}Getter", field.name.to_camel_case())).to_ident(self.span);
1083
1084 let java_class_generics: Vec<_> = self.class_generic_names();
1086
1087 let field_struct_generics: Vec<_> = java_class_generics.clone(); let field_struct = quote_spanned!(self.span =>
1094 pub struct #rust_field_type_name<
1095 #(#field_struct_generics,)*
1096 > {
1097 phantom: ::core::marker::PhantomData<(
1098 #(#field_struct_generics,)*
1099 )>,
1100 }
1101 );
1102
1103 let sig_where_clauses = &sig.where_clauses;
1104
1105 let this_ty = self.this_type();
1108 let jvmop_impl = quote_spanned!(self.span =>
1109 impl<#(#field_struct_generics),*> duchess::prelude::JvmOp
1110 for #rust_field_type_name<#(#field_struct_generics),*>
1111 where
1112 #(#java_class_generics: duchess::JavaObject,)*
1113 #(#sig_where_clauses,)*
1114 {
1115 type Output<'jvm> = #output_ty;
1116
1117 fn do_jni<'jvm>(
1118 self,
1119 jvm: &mut duchess::Jvm<'jvm>,
1120 ) -> duchess::LocalResult<'jvm, Self::Output<'jvm>> {
1121
1122 static FIELD: duchess::plumbing::once_cell::sync::OnceCell<duchess::plumbing::FieldPtr> = duchess::plumbing::once_cell::sync::OnceCell::new();
1126 let field = FIELD.get_or_try_init(|| {
1127 let class = <#this_ty as duchess::JavaObject>::class(jvm)?;
1128 duchess::plumbing::find_field(jvm, &class, #jni_field, #jni_descriptor, true)
1129 })?;
1130
1131 let class = <#this_ty as duchess::JavaObject>::class(jvm)?;
1132 unsafe {
1133 jvm.env().invoke(|env| env.#jni_field_fn, |env, f| f(
1134 env,
1135 duchess::plumbing::JavaObjectExt::as_raw(&*class).as_ptr(),
1136 field.as_ptr(),
1137 ))
1138 }
1139 }
1140 }
1141
1142 impl<#(#field_struct_generics),*> ::core::clone::Clone for #rust_field_type_name<#(#field_struct_generics),*>
1143 where
1144 #(#java_class_generics: duchess::JavaObject,)*
1145 #(#sig_where_clauses,)*
1146 {
1147 fn clone(&self) -> Self {
1148 #rust_field_type_name {
1149 phantom: self.phantom,
1150 }
1151 }
1152 }
1153 );
1154
1155 let inherent_method = quote_spanned!(self.span =>
1156 pub fn #rust_field_name() -> impl #output_trait
1157 where
1158 #(#sig_where_clauses,)*
1159 {
1160 #field_struct
1161
1162 #jvmop_impl
1163
1164 #rust_field_type_name {
1165 phantom: ::core::default::Default::default(),
1166 }
1167 }
1168 );
1169
1170 Ok(inherent_method)
1174 }
1175
1176 fn struct_name(&self) -> Ident {
1177 self.name.class_name().to_ident(self.span)
1178 }
1179
1180 fn class_generic_names(&self) -> Vec<Ident> {
1181 self.generics
1182 .iter()
1183 .map(|g| g.to_ident(self.span))
1184 .collect()
1185 }
1186
1187 fn class_generic_names_with_defaults(&self) -> Vec<TokenStream> {
1188 self.class_generic_names()
1189 .into_iter()
1190 .map(|g| quote_spanned!(self.span => #g = java::lang::Object))
1191 .collect()
1192 }
1193
1194 fn this_type(&self) -> TokenStream {
1195 let s = self.struct_name();
1196 if self.generics.is_empty() {
1197 quote_spanned!(self.span => #s)
1198 } else {
1199 let g: Vec<Ident> = self.class_generic_names();
1200 quote_spanned!(self.span => #s < #(#g),* >)
1201 }
1202 }
1203
1204 fn jni_class_name(&self) -> TokenStream {
1206 jni_c_str(self.name.to_jni_name(), self.span)
1207 }
1208
1209 fn prepare_inputs(&self, input_names: &[Ident], input_types: &[Type]) -> Vec<TokenStream> {
1210 input_names
1211 .iter()
1212 .zip(input_types)
1213 .map(|(input_name, input_ty)| match input_ty.to_non_repeating() {
1214 NonRepeatingType::Scalar(_) => quote_spanned!(self.span =>
1215 let #input_name = self.#input_name.do_jni(jvm)?;
1216 ),
1217 NonRepeatingType::Ref(_) => {
1218 quote_spanned!(self.span =>
1219 let #input_name = self.#input_name.into_as_jref(jvm)?;
1220 let #input_name = match duchess::prelude::AsJRef::as_jref(&#input_name) {
1221 Ok(v) => Some(v),
1222 Err(duchess::NullJRef) => None,
1223 };
1224 )
1225 }
1226 })
1227 .collect()
1228 }
1229}
1230
1231fn jni_c_str(contents: impl Into<String>, span: Span) -> TokenStream {
1232 let mut contents = contents.into().into_bytes();
1233 contents.push(0);
1235
1236 let byte_string = Literal::byte_string(&contents);
1237 quote_spanned!(span => unsafe { ::core::ffi::CStr::from_bytes_with_nul_unchecked(#byte_string) })
1238}