toad_jni/java/
ty.rs

1use std::fmt::Display;
2
3use jni::objects::{GlobalRef, JObject};
4
5use super::{Class, NoUpcast};
6use crate::java;
7
8/// Provides strongly-typed JVM type signature strings at compile-time
9///
10/// A `Signature` can be obtained for all [`Type`] via [`Signature::of`]:
11/// ```
12/// use toad_jni::java;
13///
14/// assert_eq!(java::Signature::of::<i32>().as_str(), "I");
15/// assert_eq!(java::Signature::of::<()>().as_str(), "V");
16///
17/// type SumBigInts = fn(Vec<java::math::BigInteger>) -> java::math::BigInteger;
18/// assert_eq!(java::Signature::of::<SumBigInts>().as_str(),
19///            "([Ljava/math/BigInteger;)Ljava/math/BigInteger;");
20/// ```
21#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
22pub struct Signature {
23  bytes: [u8; 256],
24  len: usize,
25  finished: bool,
26}
27
28impl Signature {
29  const CLASS_PATH_OPEN: Self = Self::empty().push_str("L");
30  const CLASS_PATH_CLOSE: Self = Self::empty().push_str(";");
31  const ARRAY_OF: Self = Self::empty().push_str("[");
32  const ARGS_OPEN: Self = Self::empty().push_str("(");
33  const ARGS_CLOSE: Self = Self::empty().push_str(")");
34
35  /// Get the `Signature` instance for type `T`
36  pub const fn of<T>() -> Self
37    where T: Type
38  {
39    T::SIG
40  }
41
42  /// Get the [`jni::signature::ReturnType`] of a function [`Signature`]
43  pub fn return_type(self) -> jni::signature::ReturnType {
44    use jni::signature::Primitive::*;
45    use jni::signature::ReturnType::*;
46
47    let ret = self.as_str();
48    let ret = ret.split(')')
49                 .nth(1)
50                 .unwrap_or_else(|| panic!("{:?} is not a function signature", self));
51
52    if ret.starts_with(Self::ARRAY_OF.as_str()) {
53      Array
54    } else if ret.starts_with(Self::CLASS_PATH_OPEN.as_str()) {
55      Object
56    } else {
57      Primitive(match Signature::empty().push_str(ret) {
58                  | <()>::SIG => Void,
59                  | bool::SIG => Boolean,
60                  | u16::SIG => Char,
61                  | i8::SIG => Byte,
62                  | i16::SIG => Short,
63                  | i32::SIG => Int,
64                  | i64::SIG => Long,
65                  | f32::SIG => Float,
66                  | f64::SIG => Double,
67                  | _ => unreachable!(),
68                })
69    }
70  }
71
72  const fn empty() -> Self {
73    Self { bytes: [0; 256],
74           len: 0,
75           finished: false }
76  }
77
78  pub(crate) const fn function() -> Self {
79    Self::empty().concat(Self::ARGS_OPEN)
80  }
81
82  const fn array_of(t: Self) -> Self {
83    Self::empty().concat(Self::ARRAY_OF).concat(t)
84  }
85
86  const fn class(path: &'static str) -> Self {
87    Self::empty().concat(Self::CLASS_PATH_OPEN)
88                 .push_str(path)
89                 .concat(Self::CLASS_PATH_CLOSE)
90  }
91
92  const fn next(&self) -> usize {
93    self.len
94  }
95
96  pub(crate) const fn concat(mut self, other: Signature) -> Self {
97    let mut i = 0;
98    loop {
99      if i == other.len {
100        break;
101      }
102      self = self.push_byte(other.bytes[i]);
103      i += 1;
104    }
105
106    self
107  }
108
109  const fn push_byte(mut self, b: u8) -> Self {
110    if self.finished {
111      panic!("cannot modify Sig after invoking .ret()")
112    }
113    let n = self.next();
114    self.bytes[n] = b;
115    self.len += 1;
116    self
117  }
118
119  const fn push_str(mut self, s: &str) -> Self {
120    let mut i = 0;
121    loop {
122      if i == s.len() {
123        break;
124      }
125
126      let b = s.as_bytes()[i];
127      self = self.push_byte(b);
128
129      i += 1;
130    }
131
132    self
133  }
134
135  pub(crate) const fn ret(mut self, ret: Self) -> Self {
136    self = self.concat(Self::ARGS_CLOSE).concat(ret);
137    self.finished = true;
138    self
139  }
140
141  /// Convert a [`Signature`] reference to [`str`]
142  pub fn as_str(&self) -> &str {
143    match core::str::from_utf8(&self.bytes[0..self.len]) {
144      | Ok(s) => s,
145      | _ => unreachable!(),
146    }
147  }
148}
149
150impl Display for Signature {
151  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
152    write!(f, "{}", self.as_str())
153  }
154}
155
156impl AsRef<str> for Signature {
157  fn as_ref(&self) -> &str {
158    self.as_str()
159  }
160}
161
162mod type_sealed {
163  use jni::objects::GlobalRef;
164
165  use crate::java;
166
167  #[allow(unreachable_pub)]
168  pub trait TypeSealed {}
169  impl<T> TypeSealed for T where T: java::Class {}
170  impl<T> TypeSealed for Result<T, java::lang::Throwable> where T: java::Type {}
171  impl<T> TypeSealed for Vec<T> where T: java::Type {}
172  impl<R> TypeSealed for fn() -> R where R: java::Type {}
173  impl<A, R> TypeSealed for fn(A) -> R where R: java::Type {}
174  impl<A, B, R> TypeSealed for fn(A, B) -> R where R: java::Type {}
175  impl<A, B, C, R> TypeSealed for fn(A, B, C) -> R where R: java::Type {}
176  impl<A, B, C, D, R> TypeSealed for fn(A, B, C, D) -> R where R: java::Type {}
177  impl<A, B, C, D, E, R> TypeSealed for fn(A, B, C, D, E) -> R where R: java::Type {}
178  impl TypeSealed for GlobalRef {}
179  impl TypeSealed for () {}
180  impl TypeSealed for u16 {}
181  impl TypeSealed for bool {}
182  impl TypeSealed for i8 {}
183  impl TypeSealed for i16 {}
184  impl TypeSealed for i32 {}
185  impl TypeSealed for i64 {}
186  impl TypeSealed for f32 {}
187  impl TypeSealed for f64 {}
188}
189
190/// A type that has a corresponding Java type
191///
192/// ## Sealed
193/// You can't implement this trait directly; instead you can define new
194/// [`java::Class`]es, which will then come with [`Type`] implementations for free.
195///
196/// ## Conversions
197/// |rust type|java type|notes|
198/// |--|--|--|
199/// |`T where T: `[`java::Class`]|fully qualified class path||
200/// |[`Result`]`<T, `[`java::lang::Throwable`]`>`|`T::PATH`|[`java::Class`] must be implemented for `T`|
201/// |[`java::Nullable`]`<T>`|`T::PATH`|[`java::Class`] must be implemented for `T`|
202/// |[`java::NoUpcast`]`<T>`|`java::lang::Object`|[`java::Class`] must be implemented for `T`. Used when a method should have the signature of returning `T`, but you would like the object reference without [`java::Object::upcast`]ing.|
203/// |[`java::lang::Object`]|`java.lang.Object`||
204/// |[`Vec`]`<T>`|`T[]`|`T` must be [`java::Type`]|
205/// |[`String`]|`java.lang.String`|[`java::Class`] and [`java::Object`] implemented for [`String`]|
206/// |`()`|`void`||
207/// |`u16`|`char`||
208/// |`i8`|`byte`||
209/// |`i16`|`short`||
210/// |`i32`|`int`||
211/// |`i64`|`long`||
212/// |`f32`|`float`||
213/// |`f64`|`double`||
214/// |`fn(T,*) -> R`|corresponding java type signature|all argument types and return types must be [`java::Type`]|
215pub trait Type: type_sealed::TypeSealed {
216  /// The signature for this type
217  const SIG: Signature;
218
219  /// Determines whether an object is an instance of this type
220  fn is_type_of(e: &mut java::Env, o: &JObject) -> bool {
221    e.is_instance_of(o, Self::SIG).unwrap()
222  }
223
224  /// Get the [`jni`] rep of this type
225  fn jni() -> jni::signature::JavaType;
226}
227
228impl<T> Type for T where T: java::Class
229{
230  const SIG: Signature = Signature::class(T::PATH);
231  fn jni() -> jni::signature::JavaType {
232    jni::signature::JavaType::Object(T::PATH.into())
233  }
234}
235
236impl<T> Type for Result<T, java::lang::Throwable> where T: java::Class
237{
238  const SIG: Signature = Signature::class(T::PATH);
239  fn jni() -> jni::signature::JavaType {
240    jni::signature::JavaType::Object(T::PATH.into())
241  }
242}
243
244impl Type for GlobalRef {
245  const SIG: Signature = java::lang::Object::SIG;
246  fn jni() -> jni::signature::JavaType {
247    jni::signature::JavaType::Object(java::lang::Object::PATH.into())
248  }
249}
250
251impl Type for () {
252  const SIG: Signature = Signature::empty().push_str("V");
253  fn jni() -> jni::signature::JavaType {
254    jni::signature::JavaType::Primitive(jni::signature::Primitive::Void)
255  }
256}
257
258impl Type for u16 {
259  const SIG: Signature = Signature::empty().push_str("C");
260  fn jni() -> jni::signature::JavaType {
261    jni::signature::JavaType::Primitive(jni::signature::Primitive::Char)
262  }
263}
264
265impl Type for i8 {
266  const SIG: Signature = Signature::empty().push_str("B");
267  fn jni() -> jni::signature::JavaType {
268    jni::signature::JavaType::Primitive(jni::signature::Primitive::Byte)
269  }
270}
271
272impl Type for i16 {
273  const SIG: Signature = Signature::empty().push_str("S");
274  fn jni() -> jni::signature::JavaType {
275    jni::signature::JavaType::Primitive(jni::signature::Primitive::Short)
276  }
277}
278
279impl Type for i32 {
280  const SIG: Signature = Signature::empty().push_str("I");
281  fn jni() -> jni::signature::JavaType {
282    jni::signature::JavaType::Primitive(jni::signature::Primitive::Int)
283  }
284}
285
286impl Type for i64 {
287  const SIG: Signature = Signature::empty().push_str("J");
288  fn jni() -> jni::signature::JavaType {
289    jni::signature::JavaType::Primitive(jni::signature::Primitive::Long)
290  }
291}
292
293impl Type for f32 {
294  const SIG: Signature = Signature::empty().push_str("F");
295  fn jni() -> jni::signature::JavaType {
296    jni::signature::JavaType::Primitive(jni::signature::Primitive::Float)
297  }
298}
299
300impl Type for f64 {
301  const SIG: Signature = Signature::empty().push_str("D");
302  fn jni() -> jni::signature::JavaType {
303    jni::signature::JavaType::Primitive(jni::signature::Primitive::Double)
304  }
305}
306
307impl Type for bool {
308  const SIG: Signature = Signature::empty().push_str("Z");
309  fn jni() -> jni::signature::JavaType {
310    jni::signature::JavaType::Primitive(jni::signature::Primitive::Boolean)
311  }
312}
313
314impl<T> Type for Vec<T> where T: Type
315{
316  const SIG: Signature = Signature::array_of(T::SIG);
317  fn jni() -> jni::signature::JavaType {
318    jni::signature::JavaType::Array(Box::new(T::jni()))
319  }
320}
321
322impl<R> Type for fn() -> R where R: Type
323{
324  const SIG: Signature = Signature::function().ret(R::SIG);
325  fn jni() -> jni::signature::JavaType {
326    jni::signature::JavaType::Method(Box::new(jni::signature::TypeSignature { args: vec![], ret: Self::SIG.return_type() }))
327  }
328}
329
330impl<R, A> Type for fn(A) -> R
331  where R: Type,
332        A: Type
333{
334  const SIG: Signature = Signature::function().concat(A::SIG).ret(R::SIG);
335  fn jni() -> jni::signature::JavaType {
336    jni::signature::JavaType::Method(Box::new(jni::signature::TypeSignature { args: vec![A::jni()], ret: Self::SIG.return_type() }))
337  }
338}
339
340impl<R, A, B> Type for fn(A, B) -> R
341  where R: Type,
342        A: Type,
343        B: Type
344{
345  const SIG: Signature = Signature::function().concat(A::SIG)
346                                              .concat(B::SIG)
347                                              .ret(R::SIG);
348  fn jni() -> jni::signature::JavaType {
349    jni::signature::JavaType::Method(Box::new(jni::signature::TypeSignature { args: vec![A::jni(), B::jni()], ret: Self::SIG.return_type() }))
350  }
351}
352
353impl<R, A, B, C> Type for fn(A, B, C) -> R
354  where R: Type,
355        A: Type,
356        B: Type,
357        C: Type
358{
359  const SIG: Signature = Signature::function().concat(A::SIG)
360                                              .concat(B::SIG)
361                                              .concat(C::SIG)
362                                              .ret(R::SIG);
363  fn jni() -> jni::signature::JavaType {
364    jni::signature::JavaType::Method(Box::new(jni::signature::TypeSignature { args: vec![A::jni(), B::jni(), C::jni()], ret: Self::SIG.return_type() }))
365  }
366}
367
368impl<R, A, B, C, D> Type for fn(A, B, C, D) -> R
369  where R: Type,
370        A: Type,
371        B: Type,
372        C: Type,
373        D: Type
374{
375  const SIG: Signature = Signature::function().concat(A::SIG)
376                                              .concat(B::SIG)
377                                              .concat(C::SIG)
378                                              .concat(D::SIG)
379                                              .ret(R::SIG);
380  fn jni() -> jni::signature::JavaType {
381    jni::signature::JavaType::Method(Box::new(jni::signature::TypeSignature { args: vec![A::jni(), B::jni(), C::jni(), D::jni()], ret: Self::SIG.return_type() }))
382  }
383}
384
385impl<R, A, B, C, D, E> Type for fn(A, B, C, D, E) -> R
386  where R: Type,
387        A: Type,
388        B: Type,
389        C: Type,
390        D: Type,
391        E: Type
392{
393  const SIG: Signature = Signature::function().concat(A::SIG)
394                                              .concat(B::SIG)
395                                              .concat(C::SIG)
396                                              .concat(D::SIG)
397                                              .concat(E::SIG)
398                                              .ret(R::SIG);
399  fn jni() -> jni::signature::JavaType {
400    jni::signature::JavaType::Method(Box::new(jni::signature::TypeSignature { args: vec![A::jni(), B::jni(), C::jni(), D::jni(), E::jni()], ret: Self::SIG.return_type() }))
401  }
402}
403
404#[cfg(test)]
405pub mod test {
406  use crate::java::Signature;
407
408  #[test]
409  fn return_type() {
410    use jni::signature::Primitive::*;
411    use jni::signature::ReturnType::*;
412
413    assert_eq!(Signature::of::<fn()>().return_type(), Primitive(Void));
414    assert_eq!(Signature::of::<fn(String) -> String>().return_type(),
415               Object);
416    assert_eq!(Signature::of::<fn(String) -> Vec<String>>().return_type(),
417               Array);
418    assert_eq!(Signature::of::<fn() -> u16>().return_type(),
419               Primitive(Char));
420    assert_eq!(Signature::of::<fn() -> bool>().return_type(),
421               Primitive(Boolean));
422    assert_eq!(Signature::of::<fn() -> i8>().return_type(), Primitive(Byte));
423    assert_eq!(Signature::of::<fn() -> i16>().return_type(),
424               Primitive(Short));
425    assert_eq!(Signature::of::<fn() -> i32>().return_type(), Primitive(Int));
426    assert_eq!(Signature::of::<fn() -> i64>().return_type(),
427               Primitive(Long));
428    assert_eq!(Signature::of::<fn() -> f32>().return_type(),
429               Primitive(Float));
430    assert_eq!(Signature::of::<fn() -> f64>().return_type(),
431               Primitive(Double));
432  }
433}