toad_jni/java/
function.rs

1#![allow(clippy::too_many_arguments)]
2
3use core::marker::PhantomData;
4use std::sync::RwLock;
5
6use java::{Class, Object, ResultExt, Signature, Type};
7use jni::objects::{GlobalRef, JClass, JMethodID, JObject, JStaticMethodID};
8
9use crate::java;
10
11/// Static high-level wrapper of Java class instance methods
12///
13/// See the [module documentation](crate::java) for examples.
14pub struct Method<C, F> {
15  name: &'static str,
16  mid: RwLock<Option<JMethodID>>,
17  _t: PhantomData<(C, F)>,
18}
19
20impl<C, F> Method<C, F>
21  where F: Type,
22        C: Class
23{
24  /// Create a new method lens that invokes the method named `name` on class `C`.
25  ///
26  /// If you want to invoke a potentially overridden method definition on the
27  /// object instances, use [`Method::new_overrideable`]
28  pub const fn new(name: &'static str) -> Self {
29    Self { name,
30           mid: RwLock::new(None),
31           _t: PhantomData }
32  }
33
34  /// Get & cache the method ID for this method
35  fn find(&self, e: &mut java::Env) -> JMethodID {
36    let mid = self.mid.read().unwrap();
37
38    if mid.is_none() {
39      drop(mid);
40      let mid = e.get_method_id(C::PATH, self.name, F::SIG).unwrap_java(e);
41      let mut field = self.mid.write().unwrap();
42      *field = Some(mid);
43      mid
44    } else {
45      mid.unwrap()
46    }
47  }
48}
49
50impl<C, FR> Method<C, fn() -> FR>
51  where C: Class,
52        FR: Object
53{
54  /// Call the method
55  pub fn invoke(&self, e: &mut java::Env, inst: &C) -> FR {
56    let inst = inst.downcast_ref(e);
57    let mid = self.find(e);
58    let jv = unsafe {
59      e.call_method_unchecked(&inst, mid, Signature::of::<fn() -> FR>().return_type(), &[])
60       .unwrap_java(e)
61    };
62
63    FR::upcast_value(e, jv)
64  }
65}
66
67impl<C, FA, FR> Method<C, fn(FA) -> FR>
68  where C: Class,
69        FA: Object,
70        FR: Object
71{
72  /// Call the method
73  pub fn invoke(&self, e: &mut java::Env, inst: &C, fa: FA) -> FR {
74    let inst = inst.downcast_ref(e);
75    let fa = fa.downcast_value(e);
76    let mid = self.find(e);
77    let jv = unsafe {
78      e.call_method_unchecked(&inst,
79                              mid,
80                              Signature::of::<fn(FA) -> FR>().return_type(),
81                              &[fa.as_jni()])
82       .unwrap_java(e)
83    };
84    FR::upcast_value(e, jv)
85  }
86}
87
88impl<C, FA, FB, FR> Method<C, fn(FA, FB) -> FR>
89  where C: Class,
90        FA: Object,
91        FB: Object,
92        FR: Object
93{
94  /// Call the method
95  pub fn invoke(&self, e: &mut java::Env, inst: &C, fa: FA, fb: FB) -> FR {
96    let inst = inst.downcast_ref(e);
97    let (fa, fb) = (fa.downcast_value(e), fb.downcast_value(e));
98    let mid = self.find(e);
99    let jv = unsafe {
100      e.call_method_unchecked(&inst,
101                              mid,
102                              Signature::of::<fn(FA, FB) -> FR>().return_type(),
103                              &[fa.as_jni(), fb.as_jni()])
104       .unwrap_java(e)
105    };
106    FR::upcast_value(e, jv)
107  }
108}
109
110impl<C, FA, FB, FC, FR> Method<C, fn(FA, FB, FC) -> FR>
111  where C: Class,
112        FA: Object,
113        FB: Object,
114        FC: Object,
115        FR: Object
116{
117  /// Call the method
118  pub fn invoke(&self, e: &mut java::Env, inst: &C, fa: FA, fb: FB, fc: FC) -> FR {
119    let inst = inst.downcast_ref(e);
120    let (fa, fb, fc) = (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e));
121    let mid = self.find(e);
122    let jv = unsafe {
123      e.call_method_unchecked(&inst,
124                              mid,
125                              Signature::of::<fn(FA, FB, FC) -> FR>().return_type(),
126                              &[fa.as_jni(), fb.as_jni(), fc.as_jni()])
127       .unwrap_java(e)
128    };
129    FR::upcast_value(e, jv)
130  }
131}
132
133impl<C, FA, FB, FC, FD, FR> Method<C, fn(FA, FB, FC, FD) -> FR>
134  where C: Class,
135        FA: Object,
136        FB: Object,
137        FC: Object,
138        FD: Object,
139        FR: Object
140{
141  /// Call the method
142  pub fn invoke(&self, e: &mut java::Env, inst: &C, fa: FA, fb: FB, fc: FC, fd: FD) -> FR {
143    let inst = inst.downcast_ref(e);
144    let (fa, fb, fc, fd) =
145      (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e), fd.downcast_value(e));
146    let mid = self.find(e);
147    let jv = unsafe {
148      e.call_method_unchecked(&inst,
149                              mid,
150                              Signature::of::<fn(FA, FB, FC, FD) -> FR>().return_type(),
151                              &[fa.as_jni(), fb.as_jni(), fc.as_jni(), fd.as_jni()])
152       .unwrap_java(e)
153    };
154    FR::upcast_value(e, jv)
155  }
156}
157
158impl<C, FA, FB, FC, FD, FE, FR> Method<C, fn(FA, FB, FC, FD, FE) -> FR>
159  where C: Class,
160        FA: Object,
161        FB: Object,
162        FC: Object,
163        FD: Object,
164        FE: Object,
165        FR: Object
166{
167  /// Call the method
168  pub fn invoke(&self, e: &mut java::Env, inst: &C, fa: FA, fb: FB, fc: FC, fd: FD, fe: FE) -> FR {
169    let inst = inst.downcast_ref(e);
170    let (fa, fb, fc, fd, fe) = (fa.downcast_value(e),
171                                fb.downcast_value(e),
172                                fc.downcast_value(e),
173                                fd.downcast_value(e),
174                                fe.downcast_value(e));
175    let mid = self.find(e);
176    let jv = unsafe {
177      e.call_method_unchecked(&inst,
178                              mid,
179                              Signature::of::<fn(FA, FB, FC, FD, FE) -> FR>().return_type(),
180                              &[fa.as_jni(),
181                                fb.as_jni(),
182                                fc.as_jni(),
183                                fd.as_jni(),
184                                fe.as_jni()])
185       .unwrap_java(e)
186    };
187    FR::upcast_value(e, jv)
188  }
189}
190
191impl<C, FR> Method<C, fn() -> Result<FR, java::lang::Throwable>>
192  where C: Class,
193        FR: Class
194{
195  /// Call the method
196  pub fn invoke(&self, e: &mut java::Env, inst: &C) -> Result<FR, java::lang::Throwable> {
197    let inst = inst.downcast_ref(e);
198    let mid = self.find(e);
199    unsafe {
200      e.call_method_unchecked(&inst, mid, Signature::of::<fn() -> FR>().return_type(), &[])
201       .to_throwable(e)
202       .map(|jv| FR::upcast_value(e, jv))
203    }
204  }
205}
206
207impl<C, FA, FR> Method<C, fn(FA) -> Result<FR, java::lang::Throwable>>
208  where C: Class,
209        FA: Object,
210        FR: Class
211{
212  /// Call the method
213  pub fn invoke(&self, e: &mut java::Env, inst: &C, fa: FA) -> Result<FR, java::lang::Throwable> {
214    let inst = inst.downcast_ref(e);
215    let fa = fa.downcast_value(e);
216    let mid = self.find(e);
217    unsafe {
218      e.call_method_unchecked(&inst,
219                              mid,
220                              Signature::of::<fn(FA) -> FR>().return_type(),
221                              &[fa.as_jni()])
222       .to_throwable(e)
223       .map(|jv| FR::upcast_value(e, jv))
224    }
225  }
226}
227
228impl<C, FA, FB, FR> Method<C, fn(FA, FB) -> Result<FR, java::lang::Throwable>>
229  where C: Class,
230        FA: Object,
231        FB: Object,
232        FR: Class
233{
234  /// Call the method
235  pub fn invoke(&self,
236                e: &mut java::Env,
237                inst: &C,
238                fa: FA,
239                fb: FB)
240                -> Result<FR, java::lang::Throwable> {
241    let inst = inst.downcast_ref(e);
242    let (fa, fb) = (fa.downcast_value(e), fb.downcast_value(e));
243    let mid = self.find(e);
244    unsafe {
245      e.call_method_unchecked(&inst,
246                              mid,
247                              Signature::of::<fn(FA, FB) -> FR>().return_type(),
248                              &[fa.as_jni(), fb.as_jni()])
249       .to_throwable(e)
250       .map(|jv| FR::upcast_value(e, jv))
251    }
252  }
253}
254
255impl<C, FA, FB, FC, FR> Method<C, fn(FA, FB, FC) -> Result<FR, java::lang::Throwable>>
256  where C: Class,
257        FA: Object,
258        FB: Object,
259        FC: Object,
260        FR: Class
261{
262  /// Call the method
263  pub fn invoke(&self,
264                e: &mut java::Env,
265                inst: &C,
266                fa: FA,
267                fb: FB,
268                fc: FC)
269                -> Result<FR, java::lang::Throwable> {
270    let inst = inst.downcast_ref(e);
271    let (fa, fb, fc) = (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e));
272    let mid = self.find(e);
273    unsafe {
274      e.call_method_unchecked(&inst,
275                              mid,
276                              Signature::of::<fn(FA, FB, FC) -> FR>().return_type(),
277                              &[fa.as_jni(), fb.as_jni(), fc.as_jni()])
278       .to_throwable(e)
279       .map(|jv| FR::upcast_value(e, jv))
280    }
281  }
282}
283
284impl<C, FA, FB, FC, FD, FR> Method<C, fn(FA, FB, FC, FD) -> Result<FR, java::lang::Throwable>>
285  where C: Class,
286        FA: Object,
287        FB: Object,
288        FC: Object,
289        FD: Object,
290        FR: Class
291{
292  /// Call the method
293  pub fn invoke(&self,
294                e: &mut java::Env,
295                inst: &C,
296                fa: FA,
297                fb: FB,
298                fc: FC,
299                fd: FD)
300                -> Result<FR, java::lang::Throwable> {
301    let inst = inst.downcast_ref(e);
302    let (fa, fb, fc, fd) =
303      (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e), fd.downcast_value(e));
304    let mid = self.find(e);
305    unsafe {
306      e.call_method_unchecked(&inst,
307                              mid,
308                              Signature::of::<fn(FA, FB, FC, FD) -> FR>().return_type(),
309                              &[fa.as_jni(), fb.as_jni(), fc.as_jni(), fd.as_jni()])
310       .to_throwable(e)
311       .map(|jv| FR::upcast_value(e, jv))
312    }
313  }
314}
315
316impl<C, FA, FB, FC, FD, FE, FR>
317  Method<C, fn(FA, FB, FC, FD, FE) -> Result<FR, java::lang::Throwable>>
318  where C: Class,
319        FA: Object,
320        FB: Object,
321        FC: Object,
322        FD: Object,
323        FE: Object,
324        FR: Class
325{
326  /// Call the method
327  pub fn invoke(&self,
328                e: &mut java::Env,
329                inst: &C,
330                fa: FA,
331                fb: FB,
332                fc: FC,
333                fd: FD,
334                fe: FE)
335                -> Result<FR, java::lang::Throwable> {
336    let inst = inst.downcast_ref(e);
337    let (fa, fb, fc, fd, fe) = (fa.downcast_value(e),
338                                fb.downcast_value(e),
339                                fc.downcast_value(e),
340                                fd.downcast_value(e),
341                                fe.downcast_value(e));
342    let mid = self.find(e);
343    unsafe {
344      e.call_method_unchecked(&inst,
345                              mid,
346                              Signature::of::<fn(FA, FB, FC, FD, FE) -> FR>().return_type(),
347                              &[fa.as_jni(),
348                                fb.as_jni(),
349                                fc.as_jni(),
350                                fd.as_jni(),
351                                fe.as_jni()])
352       .to_throwable(e)
353       .map(|jv| FR::upcast_value(e, jv))
354    }
355  }
356}
357
358/// Static high-level wrapper of static Java class methods
359///
360/// See the [module documentation](crate::java) for examples.
361pub struct StaticMethod<C, F> {
362  name: &'static str,
363  ids: RwLock<Option<(GlobalRef, JStaticMethodID)>>,
364  _t: PhantomData<(C, F)>,
365}
366
367impl<C, F> StaticMethod<C, F>
368  where F: Type,
369        C: Class
370{
371  /// Create the static method lens
372  pub const fn new(name: &'static str) -> Self {
373    Self { name,
374           ids: RwLock::new(None),
375           _t: PhantomData }
376  }
377
378  /// Get & cache the method ID for this method
379  fn find(&self, e: &mut java::Env) -> (JClass, JStaticMethodID) {
380    let ids = self.ids.read().unwrap();
381
382    if ids.is_none() {
383      drop(ids);
384      let class = e.find_class(C::PATH).unwrap_java(e);
385      let class = e.new_global_ref(class).unwrap_java(e);
386      let mid = e.get_static_method_id(C::PATH, self.name, F::SIG)
387                 .unwrap_java(e);
388      let mut field = self.ids.write().unwrap();
389      *field = Some((class, mid));
390      drop(field);
391      self.find(e)
392    } else {
393      let (g, mid) = ids.as_ref().unwrap();
394
395      // SAFETY: this reference never escapes this module and will not be wrapped in AutoLocal
396      // (which is the only UB risk with casting a GlobalRef to an owned JObject)
397      let jobj = unsafe { JObject::from_raw(g.as_obj().as_raw()) };
398
399      (jobj.into(), *mid)
400    }
401  }
402}
403
404impl<C, FR> StaticMethod<C, fn() -> FR>
405  where C: Class,
406        FR: Object
407{
408  /// Invoke the static method
409  pub fn invoke(&self, e: &mut java::Env) -> FR {
410    let (class, mid) = self.find(e);
411    let jv = unsafe {
412      e.call_static_method_unchecked(class, mid, Signature::of::<fn() -> FR>().return_type(), &[])
413       .unwrap_java(e)
414    };
415    FR::upcast_value(e, jv)
416  }
417}
418
419impl<C, FA, FR> StaticMethod<C, fn(FA) -> FR>
420  where C: Class,
421        FA: Object,
422        FR: Object
423{
424  /// Invoke the static method
425  pub fn invoke(&self, e: &mut java::Env, fa: FA) -> FR {
426    let fa = fa.downcast_value(e);
427    let (class, mid) = self.find(e);
428    let jv = unsafe {
429      e.call_static_method_unchecked(class,
430                                     mid,
431                                     Signature::of::<fn(FA) -> FR>().return_type(),
432                                     &[fa.as_jni()])
433       .unwrap_java(e)
434    };
435    FR::upcast_value(e, jv)
436  }
437}
438
439impl<C, FA, FB, FR> StaticMethod<C, fn(FA, FB) -> FR>
440  where C: Class,
441        FA: Object,
442        FB: Object,
443        FR: Object
444{
445  /// Invoke the static method
446  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB) -> FR {
447    let (fa, fb) = (fa.downcast_value(e), fb.downcast_value(e));
448    let (class, mid) = self.find(e);
449    let jv = unsafe {
450      e.call_static_method_unchecked(class,
451                                     mid,
452                                     Signature::of::<fn(FA, FB) -> FR>().return_type(),
453                                     &[fa.as_jni(), fb.as_jni()])
454       .unwrap_java(e)
455    };
456    FR::upcast_value(e, jv)
457  }
458}
459
460impl<C, FA, FB, FC, FR> StaticMethod<C, fn(FA, FB, FC) -> FR>
461  where C: Class,
462        FA: Object,
463        FB: Object,
464        FC: Object,
465        FR: Object
466{
467  /// Invoke the static method
468  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB, fc: FC) -> FR {
469    let (fa, fb, fc) = (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e));
470    let (class, mid) = self.find(e);
471    let jv = unsafe {
472      e.call_static_method_unchecked(class,
473                                     mid,
474                                     Signature::of::<fn(FA, FB, FC) -> FR>().return_type(),
475                                     &[fa.as_jni(), fb.as_jni(), fc.as_jni()])
476       .unwrap_java(e)
477    };
478    FR::upcast_value(e, jv)
479  }
480}
481
482impl<C, FA, FB, FC, FD, FR> StaticMethod<C, fn(FA, FB, FC, FD) -> FR>
483  where C: Class,
484        FA: Object,
485        FB: Object,
486        FC: Object,
487        FD: Object,
488        FR: Object
489{
490  /// Invoke the static method
491  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB, fc: FC, fd: FD) -> FR {
492    let (fa, fb, fc, fd) =
493      (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e), fd.downcast_value(e));
494    let (class, mid) = self.find(e);
495    let jv = unsafe {
496      e.call_static_method_unchecked(class,
497                                     mid,
498                                     Signature::of::<fn(FA, FB, FC, FD) -> FR>().return_type(),
499                                     &[fa.as_jni(), fb.as_jni(), fc.as_jni(), fd.as_jni()])
500       .unwrap_java(e)
501    };
502    FR::upcast_value(e, jv)
503  }
504}
505
506impl<C, FA, FB, FC, FD, FE, FR> StaticMethod<C, fn(FA, FB, FC, FD, FE) -> FR>
507  where C: Class,
508        FA: Object,
509        FB: Object,
510        FC: Object,
511        FD: Object,
512        FE: Object,
513        FR: Object
514{
515  /// Invoke the static method
516  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB, fc: FC, fd: FD, fe: FE) -> FR {
517    let (fa, fb, fc, fd, fe) = (fa.downcast_value(e),
518                                fb.downcast_value(e),
519                                fc.downcast_value(e),
520                                fd.downcast_value(e),
521                                fe.downcast_value(e));
522    let (class, mid) = self.find(e);
523    let jv = unsafe {
524      e.call_static_method_unchecked(class,
525                                     mid,
526                                     Signature::of::<fn(FA, FB, FC, FD, FE) -> FR>().return_type(),
527                                     &[fa.as_jni(),
528                                       fb.as_jni(),
529                                       fc.as_jni(),
530                                       fd.as_jni(),
531                                       fe.as_jni()])
532       .unwrap_java(e)
533    };
534    FR::upcast_value(e, jv)
535  }
536}
537
538impl<C, FR> StaticMethod<C, fn() -> Result<FR, java::lang::Throwable>>
539  where C: Class,
540        FR: Class
541{
542  /// Invoke the static method
543  pub fn invoke(&self, e: &mut java::Env) -> Result<FR, java::lang::Throwable> {
544    let (class, mid) = self.find(e);
545    unsafe {
546      e.call_static_method_unchecked(class, mid, Signature::of::<fn() -> Result<FR, java::lang::Throwable>>().return_type(), &[])
547       .to_throwable(e).map(|jv| FR::upcast_value(e, jv))
548    }
549  }
550}
551
552impl<C, FA, FR> StaticMethod<C, fn(FA) -> Result<FR, java::lang::Throwable>>
553  where C: Class,
554        FA: Object,
555        FR: Class
556{
557  /// Invoke the static method
558  pub fn invoke(&self, e: &mut java::Env, fa: FA) -> Result<FR, java::lang::Throwable> {
559    let fa = fa.downcast_value(e);
560    let (class, mid) = self.find(e);
561    unsafe {
562      e.call_static_method_unchecked(class,
563                                     mid,
564                                     Signature::of::<fn(FA) -> Result<FR, java::lang::Throwable>>().return_type(),
565                                     &[fa.as_jni()])
566       .to_throwable(e).map(|jv| FR::upcast_value(e, jv))
567    }
568  }
569}
570
571impl<C, FA, FB, FR> StaticMethod<C, fn(FA, FB) -> Result<FR, java::lang::Throwable>>
572  where C: Class,
573        FA: Object,
574        FB: Object,
575        FR: Class
576{
577  /// Invoke the static method
578  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB) -> Result<FR, java::lang::Throwable> {
579    let (fa, fb) = (fa.downcast_value(e), fb.downcast_value(e));
580    let (class, mid) = self.find(e);
581    unsafe {
582      e.call_static_method_unchecked(class,
583                                     mid,
584                                     Signature::of::<fn(FA, FB) -> Result<FR, java::lang::Throwable>>().return_type(),
585                                     &[fa.as_jni(), fb.as_jni()])
586       .to_throwable(e).map(|jv| FR::upcast_value(e, jv))
587    }
588  }
589}
590
591impl<C, FA, FB, FC, FR> StaticMethod<C, fn(FA, FB, FC) -> Result<FR, java::lang::Throwable>>
592  where C: Class,
593        FA: Object,
594        FB: Object,
595        FC: Object,
596        FR: Class
597{
598  /// Invoke the static method
599  pub fn invoke(&self,
600                e: &mut java::Env,
601                fa: FA,
602                fb: FB,
603                fc: FC)
604                -> Result<FR, java::lang::Throwable> {
605    let (fa, fb, fc) = (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e));
606    let (class, mid) = self.find(e);
607    unsafe {
608      e.call_static_method_unchecked(class,
609                                     mid,
610                                     Signature::of::<fn(FA, FB, FC) -> Result<FR, java::lang::Throwable>>().return_type(),
611                                     &[fa.as_jni(), fb.as_jni(), fc.as_jni()])
612       .to_throwable(e).map(|jv| FR::upcast_value(e, jv))
613    }
614  }
615}
616
617impl<C, FA, FB, FC, FD, FR> StaticMethod<C, fn(FA, FB, FC, FD) -> Result<FR, java::lang::Throwable>>
618  where C: Class,
619        FA: Object,
620        FB: Object,
621        FC: Object,
622        FD: Object,
623        FR: Class
624{
625  /// Invoke the static method
626  pub fn invoke(&self,
627                e: &mut java::Env,
628                fa: FA,
629                fb: FB,
630                fc: FC,
631                fd: FD)
632                -> Result<FR, java::lang::Throwable> {
633    let (fa, fb, fc, fd) =
634      (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e), fd.downcast_value(e));
635    let (class, mid) = self.find(e);
636    unsafe {
637      e.call_static_method_unchecked(class,
638                                     mid,
639                                     Signature::of::<fn(FA, FB, FC, FD) -> Result<FR, java::lang::Throwable>>().return_type(),
640                                     &[fa.as_jni(), fb.as_jni(), fc.as_jni(), fd.as_jni()])
641       .to_throwable(e).map(|jv| FR::upcast_value(e, jv))
642    }
643  }
644}
645
646impl<C, FA, FB, FC, FD, FE, FR>
647  StaticMethod<C, fn(FA, FB, FC, FD, FE) -> Result<FR, java::lang::Throwable>>
648  where C: Class,
649        FA: Object,
650        FB: Object,
651        FC: Object,
652        FD: Object,
653        FE: Object,
654        FR: Class
655{
656  /// Invoke the static method
657  pub fn invoke(&self,
658                e: &mut java::Env,
659                fa: FA,
660                fb: FB,
661                fc: FC,
662                fd: FD,
663                fe: FE)
664                -> Result<FR, java::lang::Throwable> {
665    let (fa, fb, fc, fd, fe) = (fa.downcast_value(e),
666                                fb.downcast_value(e),
667                                fc.downcast_value(e),
668                                fd.downcast_value(e),
669                                fe.downcast_value(e));
670    let (class, mid) = self.find(e);
671    unsafe {
672      e.call_static_method_unchecked(class,
673                                     mid,
674                                     Signature::of::<fn(FA, FB, FC, FD, FE) -> Result<FR, java::lang::Throwable>>().return_type(),
675                                     &[fa.as_jni(),
676                                       fb.as_jni(),
677                                       fc.as_jni(),
678                                       fd.as_jni(),
679                                       fe.as_jni()])
680       .to_throwable(e).map(|jv| FR::upcast_value(e, jv))
681    }
682  }
683}
684
685/// A static high-level wrapper around Java class
686/// constructors
687///
688/// See the [module documentation](crate::java) for examples.
689pub struct Constructor<C, F> {
690  id: RwLock<Option<JMethodID>>,
691  _t: PhantomData<(C, F)>,
692}
693
694impl<C, F> Constructor<C, F>
695  where F: Type,
696        C: Class
697{
698  /// Creates the lens
699  pub const fn new() -> Self {
700    Self { id: RwLock::new(None),
701           _t: PhantomData }
702  }
703
704  /// Get & cache the method ID for this constructor
705  fn find(&self, e: &mut java::Env) -> JMethodID {
706    let mid = self.id.read().unwrap();
707
708    if mid.is_none() {
709      drop(mid);
710      let mid = e.get_method_id(C::PATH, "<init>", F::SIG).unwrap_java(e);
711      let mut field = self.id.write().unwrap();
712      *field = Some(mid);
713      mid
714    } else {
715      mid.unwrap()
716    }
717  }
718}
719
720impl<C> Constructor<C, fn()> where C: Class
721{
722  /// Invoke the constructor
723  pub fn invoke(&self, e: &mut java::Env) -> C {
724    let jobj = e.new_object(C::PATH, Signature::of::<fn()>(), &[])
725                .unwrap_java(e);
726    java::lang::Object::from_local(e, jobj).upcast_to::<C>(e)
727  }
728}
729
730impl<C, FA> Constructor<C, fn(FA)>
731  where C: Class,
732        FA: Object
733{
734  /// Invoke the constructor
735  pub fn invoke(&self, e: &mut java::Env, fa: FA) -> C {
736    let fa = fa.downcast_value(e);
737    let mid = self.find(e);
738    let jv = unsafe {
739      e.new_object_unchecked(C::PATH, mid, &[fa.as_jni()])
740       .unwrap_java(e)
741    };
742
743    java::lang::Object::from_local(e, jv).upcast_to::<C>(e)
744  }
745}
746
747impl<C, FA, FB> Constructor<C, fn(FA, FB)>
748  where C: Class,
749        FA: Object,
750        FB: Object
751{
752  /// Invoke the constructor
753  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB) -> C {
754    let (fa, fb) = (fa.downcast_value(e), fb.downcast_value(e));
755    let mid = self.find(e);
756    let jv = unsafe {
757      e.new_object_unchecked(C::PATH, mid, &[fa.as_jni(), fb.as_jni()])
758       .unwrap_java(e)
759    };
760    java::lang::Object::from_local(e, jv).upcast_to::<C>(e)
761  }
762}
763
764impl<C, FA, FB, FC> Constructor<C, fn(FA, FB, FC)>
765  where C: Class,
766        FA: Object,
767        FB: Object,
768        FC: Object
769{
770  /// Invoke the constructor
771  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB, fc: FC) -> C {
772    let (fa, fb, fc) = (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e));
773    let mid = self.find(e);
774    let jv = unsafe {
775      e.new_object_unchecked(C::PATH, mid, &[fa.as_jni(), fb.as_jni(), fc.as_jni()])
776       .unwrap_java(e)
777    };
778    java::lang::Object::from_local(e, jv).upcast_to::<C>(e)
779  }
780}
781
782impl<C, FA, FB, FC, FD> Constructor<C, fn(FA, FB, FC, FD)>
783  where C: Class,
784        FA: Object,
785        FB: Object,
786        FC: Object,
787        FD: Object
788{
789  /// Invoke the constructor
790  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB, fc: FC, fd: FD) -> C {
791    let (fa, fb, fc, fd) =
792      (fa.downcast_value(e), fb.downcast_value(e), fc.downcast_value(e), fd.downcast_value(e));
793    let mid = self.find(e);
794    let jv = unsafe {
795      e.new_object_unchecked(C::PATH,
796                             mid,
797                             &[fa.as_jni(), fb.as_jni(), fc.as_jni(), fd.as_jni()])
798       .unwrap_java(e)
799    };
800    java::lang::Object::from_local(e, jv).upcast_to::<C>(e)
801  }
802}
803
804impl<C, FA, FB, FC, FD, FE> Constructor<C, fn(FA, FB, FC, FD, FE)>
805  where C: Class,
806        FA: Object,
807        FB: Object,
808        FC: Object,
809        FD: Object,
810        FE: Object
811{
812  /// Invoke the constructor
813  pub fn invoke(&self, e: &mut java::Env, fa: FA, fb: FB, fc: FC, fd: FD, fe: FE) -> C {
814    let (fa, fb, fc, fd, fe) = (fa.downcast_value(e),
815                                fb.downcast_value(e),
816                                fc.downcast_value(e),
817                                fd.downcast_value(e),
818                                fe.downcast_value(e));
819    let mid = self.find(e);
820    let jv = unsafe {
821      e.new_object_unchecked(C::PATH,
822                             mid,
823                             &[fa.as_jni(),
824                               fb.as_jni(),
825                               fc.as_jni(),
826                               fd.as_jni(),
827                               fe.as_jni()])
828       .unwrap_java(e)
829    };
830    java::lang::Object::from_local(e, jv).upcast_to::<C>(e)
831  }
832}