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
use core::marker::PhantomData;
use std::str::FromStr;
use std::sync::RwLock;

use java::ResultExt;
use jni::objects::{JFieldID, JStaticFieldID};

use crate::java;

/// A high-level lens into a Java object field
pub struct Field<C, T> {
  name: &'static str,
  id: RwLock<Option<JFieldID>>,
  _t: PhantomData<(C, T)>,
}

impl<C, T> Field<C, T>
  where C: java::Class,
        T: java::Object
{
  /// Creates a new field lens
  pub const fn new(name: &'static str) -> Self {
    Self { name,
           id: RwLock::new(None),
           _t: PhantomData }
  }

  /// Get the value of this field
  pub fn get(&self, e: &mut java::Env, inst: &C) -> T {
    let id = self.id.read().unwrap();
    if id.is_none() {
      drop(id);

      let mut id = self.id.write().unwrap();
      *id = Some(e.get_field_id(C::PATH, self.name, T::SIG).unwrap_java(e));
      drop(id);

      self.get(e, inst)
    } else {
      let inst = inst.downcast_ref(e);
      let val =
        e.get_field_unchecked(&inst,
                              id.unwrap(),
                              jni::signature::ReturnType::from_str(T::SIG.as_str()).unwrap())
         .unwrap_java(e);
      T::upcast_value(e, val)
    }
  }

  /// Set the value of this field
  pub fn set(&self, e: &mut java::Env, inst: &C, t: T) {
    let inst = inst.downcast_ref(e);
    let t = t.downcast_value(e);
    e.set_field(inst, self.name, T::SIG, (&t).into())
     .unwrap_java(e);
  }
}

/// A high-level lens into a static Java object field
pub struct StaticField<C, T> {
  name: &'static str,
  id: RwLock<Option<JStaticFieldID>>,
  _t: PhantomData<(C, T)>,
}

impl<C, T> StaticField<C, T>
  where C: java::Class,
        T: java::Object
{
  /// Creates a new static field lens
  pub const fn new(name: &'static str) -> Self {
    Self { name,
           id: RwLock::new(None),
           _t: PhantomData }
  }

  /// Get the static field value
  pub fn get(&self, e: &mut java::Env) -> T {
    let id = self.id.read().unwrap();
    if id.is_none() {
      drop(id);

      let mut id = self.id.write().unwrap();
      *id = Some(e.get_static_field_id(C::PATH, self.name, T::SIG)
                  .unwrap_java(e));
      drop(id);

      self.get(e)
    } else {
      let val = e.get_static_field_unchecked(C::PATH, id.unwrap(), T::jni())
                 .unwrap();
      T::upcast_value(e, val)
    }
  }
}