Skip to main content

toad_jni/java/math/
bigint.rs

1use std::collections::VecDeque;
2
3use crate::java;
4
5/// java/math/BigInteger
6pub struct BigInteger(java::lang::Object);
7
8impl BigInteger {
9  /// java.math.BigInteger.ONE
10  pub fn one(e: &mut java::Env) -> Self {
11    static ONE: java::StaticField<BigInteger, BigInteger> = java::StaticField::new("ONE");
12    ONE.get(e)
13  }
14
15  /// java.math.BigInteger.TWO
16  pub fn two(e: &mut java::Env) -> Self {
17    static TWO: java::StaticField<BigInteger, BigInteger> = java::StaticField::new("TWO");
18    TWO.get(e)
19  }
20
21  /// java.math.BigInteger.TEN
22  pub fn ten(e: &mut java::Env) -> Self {
23    static TEN: java::StaticField<BigInteger, BigInteger> = java::StaticField::new("TEN");
24    TEN.get(e)
25  }
26
27  /// java.math.BigInteger.ZERO
28  pub fn zero(e: &mut java::Env) -> Self {
29    static ZERO: java::StaticField<BigInteger, BigInteger> = java::StaticField::new("ZERO");
30    ZERO.get(e)
31  }
32
33  /// Interpret result of [`BigInteger::to_be_bytes`] as a i8
34  pub fn to_i8(&self, e: &mut java::Env) -> i8 {
35    let bytes = self.to_be_bytes::<1>(e);
36    i8::from_be_bytes(bytes)
37  }
38
39  /// Interpret result of [`BigInteger::to_be_bytes`] as a i16
40  pub fn to_i16(&self, e: &mut java::Env) -> i16 {
41    let bytes = self.to_be_bytes::<2>(e);
42    i16::from_be_bytes(bytes)
43  }
44
45  /// Interpret result of [`BigInteger::to_be_bytes`] as a i32
46  pub fn to_i32(&self, e: &mut java::Env) -> i32 {
47    let bytes = self.to_be_bytes::<4>(e);
48    i32::from_be_bytes(bytes)
49  }
50
51  /// Interpret result of [`BigInteger::to_be_bytes`] as a i64
52  pub fn to_i64(&self, e: &mut java::Env) -> i64 {
53    let bytes = self.to_be_bytes::<8>(e);
54    i64::from_be_bytes(bytes)
55  }
56
57  /// Interpret result of [`BigInteger::to_be_bytes`] as a i128
58  pub fn to_i128(&self, e: &mut java::Env) -> i128 {
59    let bytes = self.to_be_bytes::<16>(e);
60    i128::from_be_bytes(bytes)
61  }
62
63  /// Extract the raw bytes in big-endian order of this BigInteger, panicking if negative or too big
64  pub fn to_be_bytes<const N: usize>(&self, e: &mut java::Env) -> [u8; N] {
65    static TO_BYTE_ARRAY: java::Method<BigInteger, fn() -> Vec<i8>> =
66      java::Method::new("toByteArray");
67
68    let mut bytes = VecDeque::from(TO_BYTE_ARRAY.invoke(e, self));
69
70    let mut byte_array = [0u8; N];
71
72    // if `bytes: VecDeque` is shorter than `N`,
73    // this will ensure that `byte_array` is zero-padded,
74    // and panic if there are more bytes than `N`
75
76    if let Some((first_nonzero_ix, _)) = bytes.iter().enumerate().find(|(_, b)| **b > 0) {
77      bytes.drain(0..first_nonzero_ix).for_each(|_| ());
78    }
79
80    bytes.iter()
81         .map(|i| {
82           // https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/math/BigInteger.html#toByteArray()
83           //
84           // toByteArray returns the raw byte representation
85           // of the integer, NOT i8s which are the normal
86           // interpretation for a java `byte` primitive.
87           i8::to_be_bytes(*i)[0]
88         })
89         .rfold(N - 1, |ix, b| {
90           byte_array[ix] = b;
91           ix.saturating_sub(1)
92         });
93
94    byte_array
95  }
96
97  /// Create a BigInteger from some bytes, easily gotten
98  /// for any signed rust integer (`i8`, `i16`, ..) via `.to_be_bytes()`.
99  ///
100  /// Technically, this uses `java.math.BigInteger(byte[] bytes)` to
101  /// create a `java.math.BigInteger` from an array of bytes that
102  /// must represent a signed two's complement integer, in big-endian order.
103  pub fn from_be_bytes(e: &mut java::Env, bytes: &[u8]) -> Self {
104    static CTOR_BYTE_ARRAY: java::Constructor<BigInteger, fn(Vec<i8>)> = java::Constructor::new();
105    CTOR_BYTE_ARRAY.invoke(e,
106                           bytes.iter()
107                                .copied()
108                                .map(|u| i8::from_be_bytes(u.to_be_bytes()))
109                                .collect())
110  }
111}
112
113impl java::Class for BigInteger {
114  const PATH: &'static str = "java/math/BigInteger";
115}
116
117impl java::Object for BigInteger {
118  fn upcast(_e: &mut java::Env, jobj: java::lang::Object) -> Self {
119    Self(jobj)
120  }
121
122  fn downcast(self, _e: &mut java::Env) -> java::lang::Object {
123    self.0
124  }
125
126  fn downcast_ref(&self, e: &mut java::Env) -> java::lang::Object {
127    self.0.downcast_ref(e)
128  }
129}