rustler_bigint/
big_int.rs

1use rustler::{Decoder, Encoder, Env, Error, NifResult, Term};
2
3use num_bigint::Sign;
4
5// From https://www.erlang.org/doc/apps/erts/erl_ext_dist.html
6const EXTERNAL_TERM_FORMAT_VERSION: u8 = 131;
7const SMALL_INTEGER: u8 = 97;
8const INTEGER: u8 = 98;
9const SMALL_BIG_EXT: u8 = 110;
10const LARGE_BIG_EXT: u8 = 111;
11
12rustler::atoms! {
13    big_int_encoder_invalid_bytes
14}
15
16/// Wrapper around num-bigint that implements [Decoder](rustler::Decoder) and [Encoder](rustler::Encoder) traits
17///
18/// ```rust
19/// use rustler_bigint::{BigInt, num_bigint};
20///
21/// // convert from and to the bigint wrapper
22/// let number = num_bigint::BigInt::from(12);
23/// let implements_decode_encode = BigInt::from(number.clone());
24/// let bigint = num_bigint::BigInt::from(implements_decode_encode);
25/// assert_eq!(number, bigint);
26/// ```
27///
28/// ## Examples
29///
30/// ```rust
31/// use rustler_bigint::BigInt;
32///
33/// #[rustler::nif]
34/// pub fn pow(base: BigInt, exponent: u32) -> BigInt {
35///   base.pow(exponent).into()
36/// }
37/// ```
38///
39/// ```rust
40/// use rustler::Binary;
41/// use rustler_bigint::{BigInt, num_bigint};
42///
43/// #[rustler::nif]
44/// pub fn binary_to_integer(binary: Binary) -> BigInt {
45///   num_bigint::BigInt::from_signed_bytes_be(binary.as_slice()).into()
46/// }
47/// ```
48///
49/// ```rust
50/// use rustler::{Binary, Env, NewBinary};
51/// use rustler_bigint::BigInt;
52///
53/// #[rustler::nif]
54/// pub fn integer_to_binary<'a>(env: Env<'a>, integer: BigInt) -> Binary<'a> {
55///   let bytes = integer.to_signed_bytes_be();
56///   let mut output = NewBinary::new(env, bytes.len());
57///   output.as_mut_slice().copy_from_slice(bytes.as_slice());
58///   output.into()
59/// }
60/// ```
61///
62#[derive(Debug, PartialEq, PartialOrd)]
63pub struct BigInt(num_bigint::BigInt);
64
65impl std::convert::From<num_bigint::BigInt> for BigInt {
66    fn from(big_int: num_bigint::BigInt) -> BigInt {
67        BigInt(big_int)
68    }
69}
70
71impl std::convert::From<BigInt> for num_bigint::BigInt {
72    fn from(big_int: BigInt) -> num_bigint::BigInt {
73        big_int.0
74    }
75}
76
77impl std::ops::Deref for BigInt {
78    type Target = num_bigint::BigInt;
79
80    fn deref(&self) -> &Self::Target {
81        &self.0
82    }
83}
84
85impl std::ops::DerefMut for BigInt {
86    fn deref_mut(&mut self) -> &mut Self::Target {
87        &mut self.0
88    }
89}
90
91fn decode_big_integer(input: &[u8]) -> NifResult<num_bigint::BigInt> {
92    if Some(&EXTERNAL_TERM_FORMAT_VERSION) != input.get(0) {
93        return Err(Error::BadArg);
94    }
95
96    match input[1] {
97        SMALL_INTEGER => Ok(num_bigint::BigInt::from(input[2])),
98
99        INTEGER => Ok(num_bigint::BigInt::from_signed_bytes_be(&input[2..6])),
100
101        SMALL_BIG_EXT => {
102            let n = input[2] as usize;
103            let sign = if input[3] == 0 {
104                Sign::Plus
105            } else {
106                Sign::Minus
107            };
108
109            Ok(num_bigint::BigInt::from_bytes_le(sign, &input[4..n + 4]))
110        }
111
112        LARGE_BIG_EXT => {
113            let n = u32::from_be_bytes([input[2], input[3], input[4], input[5]]) as usize;
114            let sign = if input[6] == 0 {
115                Sign::Plus
116            } else {
117                Sign::Minus
118            };
119
120            Ok(num_bigint::BigInt::from_bytes_le(sign, &input[7..n + 7]))
121        }
122
123        _ => Err(Error::BadArg),
124    }
125}
126
127fn encode_big_integer(big_int: &num_bigint::BigInt) -> Vec<u8> {
128    if let Ok(integer) = i32::try_from(big_int) {
129        let mut out = vec![EXTERNAL_TERM_FORMAT_VERSION, INTEGER];
130        out.extend(integer.to_be_bytes());
131        out
132    } else {
133        let (sign, data) = big_int.to_bytes_le();
134        let sign = if sign == Sign::Minus { 1 } else { 0 };
135
136        let mut out = vec![EXTERNAL_TERM_FORMAT_VERSION];
137        if data.len() < 256 {
138            // small big integer
139            let n = data.len() as u8;
140            out.push(SMALL_BIG_EXT);
141            out.push(n);
142        } else {
143            // large big integer
144            let n = (data.len() as u32).to_be_bytes();
145            out.push(LARGE_BIG_EXT);
146            out.extend(n);
147        };
148        out.push(sign);
149        out.extend(data);
150
151        out
152    }
153}
154
155impl<'a> Decoder<'a> for BigInt {
156    fn decode(term: Term<'a>) -> NifResult<Self> {
157        decode_big_integer(term.to_binary().as_slice()).map(BigInt)
158    }
159}
160
161impl Encoder for BigInt {
162    fn encode<'c>(&self, env: Env<'c>) -> Term<'c> {
163        // Returns error tuple if the encode_big_integer returns invalid ETF bytes
164        let binary = encode_big_integer(&self.0);
165        match env.binary_to_term(&binary) {
166            Some((term, _)) => term,
167            None => env.error_tuple(big_int_encoder_invalid_bytes()),
168        }
169    }
170}
171
172#[test]
173fn from_test() {
174    let right = BigInt::from(num_bigint::BigInt::from(123));
175    let left = BigInt(num_bigint::BigInt::from(123));
176    assert_eq!(left, right)
177}
178
179#[test]
180fn into_test() {
181    let right = BigInt(num_bigint::BigInt::from(123));
182    let left = num_bigint::BigInt::from(123);
183    assert_eq!(left, right.into())
184}
185
186#[test]
187fn deref_test() {
188    let input = BigInt(num_bigint::BigInt::from(123));
189    assert_eq!(vec![123], input.to_signed_bytes_be())
190}
191
192#[test]
193fn deref_mut_test() {
194    let expected = BigInt(num_bigint::BigInt::from(127));
195    let mut input = BigInt(num_bigint::BigInt::from(123));
196    input.set_bit(2, true);
197
198    assert_eq!(expected, input)
199}
200
201#[test]
202fn decode_small_int() {
203    // :erlang.term_to_binary(3)
204    let data = [131, 97, 3];
205
206    let expected = num_bigint::BigInt::from(3);
207
208    assert_eq!(expected, decode_big_integer(&data).unwrap());
209}
210
211#[test]
212fn decode_small_negative_int() {
213    // :erlang.term_to_binary(-5)
214    let data = [131, 98, 255, 255, 255, 251];
215
216    let expected = num_bigint::BigInt::from(-5);
217
218    assert_eq!(expected, decode_big_integer(&data).unwrap());
219}
220
221#[test]
222fn decode_normal_int() {
223    // :erlang.term_to_binary(12345)
224    let data = [131, 98, 0, 0, 48, 57];
225
226    let expected = num_bigint::BigInt::from(12345);
227
228    assert_eq!(expected, decode_big_integer(&data).unwrap());
229}
230
231#[test]
232fn decode_small_big_int() {
233    // :erlang.term_to_binary(24**120)
234    let data = [
235        131, 110, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
236        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 68, 238, 176, 235, 252,
237        240, 96, 176, 91, 142, 219, 66, 30, 177, 137, 199, 21, 191, 153, 182, 169, 73, 73,
238    ];
239
240    let expected = num_bigint::BigInt::from(24).pow(120);
241
242    assert_eq!(expected, decode_big_integer(&data).unwrap());
243}
244
245#[test]
246fn decode_negative_small_big_int() {
247    // :erlang.term_to_binary(-17**121)
248    let data = [
249        131, 110, 62, 1, 145, 35, 189, 92, 121, 166, 54, 134, 249, 187, 212, 168, 99, 15, 199, 18,
250        199, 144, 202, 125, 24, 74, 178, 7, 108, 123, 248, 46, 241, 16, 48, 69, 1, 158, 117, 115,
251        239, 213, 166, 221, 100, 3, 60, 67, 137, 0, 113, 26, 119, 247, 227, 213, 91, 112, 34, 59,
252        186, 211, 12, 168, 222, 95,
253    ];
254
255    let expected = num_bigint::BigInt::from(-17).pow(121);
256
257    assert_eq!(expected, decode_big_integer(&data).unwrap());
258}
259
260#[test]
261fn decode_large_big_int() {
262    // :erlang.term_to_binary(5**923)
263    let data = [
264        131, 111, 0, 0, 1, 12, 0, 157, 49, 35, 72, 82, 113, 71, 89, 143, 96, 245, 181, 222, 60,
265        192, 44, 126, 212, 89, 42, 70, 17, 126, 228, 141, 27, 155, 90, 226, 45, 64, 172, 156, 24,
266        197, 15, 30, 187, 15, 9, 134, 118, 177, 56, 98, 1, 252, 238, 113, 38, 174, 187, 181, 161,
267        128, 55, 122, 131, 27, 44, 224, 26, 96, 20, 60, 68, 84, 188, 139, 50, 27, 35, 46, 111, 179,
268        103, 3, 199, 16, 76, 202, 27, 108, 124, 189, 232, 63, 190, 120, 107, 231, 233, 67, 46, 164,
269        146, 45, 0, 180, 109, 22, 20, 201, 153, 9, 199, 7, 75, 91, 29, 48, 143, 191, 229, 182, 108,
270        161, 177, 245, 218, 54, 70, 12, 89, 196, 140, 138, 73, 115, 163, 249, 101, 13, 116, 117,
271        122, 72, 14, 71, 112, 6, 243, 124, 189, 51, 36, 199, 143, 80, 129, 8, 175, 54, 95, 104, 6,
272        40, 35, 244, 36, 219, 112, 129, 114, 96, 207, 37, 61, 113, 250, 82, 185, 101, 176, 68, 250,
273        128, 104, 151, 141, 54, 167, 30, 231, 244, 173, 120, 162, 209, 54, 193, 170, 19, 160, 192,
274        6, 233, 134, 70, 73, 142, 77, 174, 157, 177, 249, 210, 65, 164, 1, 27, 205, 204, 128, 251,
275        195, 234, 183, 185, 159, 191, 32, 252, 61, 28, 157, 38, 61, 130, 198, 248, 203, 196, 150,
276        186, 42, 43, 70, 136, 200, 78, 114, 229, 221, 198, 252, 187, 38, 162, 107, 52, 143, 177,
277        133, 185, 168, 30, 64, 0, 151, 20, 186, 82, 147, 226, 1, 2, 141,
278    ];
279
280    let expected = num_bigint::BigInt::from(5).pow(923);
281
282    assert_eq!(expected, decode_big_integer(&data).unwrap());
283}
284
285#[test]
286fn decode_negative_large_big_int() {
287    // :erlang.term_to_binary(-17**613)
288    let data = [
289        131, 111, 0, 0, 1, 58, 1, 81, 128, 217, 64, 63, 89, 203, 140, 179, 117, 112, 210, 237, 68,
290        55, 214, 150, 63, 212, 77, 220, 75, 154, 120, 104, 18, 185, 178, 140, 7, 210, 84, 65, 183,
291        69, 128, 159, 165, 220, 21, 229, 65, 80, 122, 240, 162, 174, 250, 62, 222, 203, 58, 15,
292        215, 204, 106, 9, 213, 233, 208, 173, 124, 143, 108, 209, 19, 246, 224, 143, 58, 151, 72,
293        57, 203, 232, 159, 92, 71, 8, 128, 138, 187, 209, 239, 209, 189, 91, 50, 55, 3, 226, 214,
294        68, 115, 187, 151, 51, 139, 199, 133, 72, 135, 158, 46, 43, 168, 141, 235, 151, 168, 127,
295        2, 17, 73, 195, 85, 131, 34, 150, 45, 210, 55, 18, 192, 113, 207, 229, 131, 213, 56, 48,
296        60, 112, 76, 231, 109, 95, 46, 73, 56, 133, 2, 78, 96, 124, 119, 255, 5, 70, 120, 18, 146,
297        6, 102, 190, 157, 134, 72, 125, 98, 88, 182, 38, 21, 13, 165, 135, 45, 143, 43, 121, 101,
298        213, 130, 203, 180, 216, 230, 52, 163, 168, 125, 130, 100, 246, 179, 75, 211, 165, 66, 252,
299        232, 223, 119, 44, 105, 62, 1, 100, 61, 132, 185, 114, 75, 234, 116, 186, 208, 227, 77, 81,
300        18, 76, 125, 131, 116, 70, 180, 112, 76, 46, 36, 44, 243, 131, 190, 143, 166, 93, 72, 55,
301        1, 92, 19, 242, 248, 90, 209, 160, 223, 191, 15, 167, 89, 34, 45, 252, 219, 235, 190, 232,
302        32, 144, 232, 82, 173, 238, 213, 14, 157, 168, 162, 122, 24, 114, 192, 77, 18, 167, 147,
303        136, 239, 98, 85, 107, 86, 161, 156, 221, 20, 86, 1, 183, 233, 166, 236, 96, 181, 90, 197,
304        147, 189, 201, 71, 78, 206, 232, 115, 109, 222, 150, 213, 195, 164, 66, 123, 47, 151, 111,
305        193, 165, 1, 16, 3,
306    ];
307
308    let expected = num_bigint::BigInt::from(-17).pow(613);
309
310    assert_eq!(expected, decode_big_integer(&data).unwrap());
311}
312
313#[test]
314fn encode_positive_int_as_integer() {
315    let expected = vec![131, 98, 0, 0, 0, 12];
316
317    let input = num_bigint::BigInt::from(12);
318
319    assert_eq!(expected, encode_big_integer(&input));
320}
321
322#[test]
323fn encode_negative_int_as_integer() {
324    let expected = vec![131, 98, 255, 255, 254, 254];
325
326    let input = num_bigint::BigInt::from(-258);
327
328    assert_eq!(expected, encode_big_integer(&input));
329}
330
331#[test]
332fn encode_negative_int_just_outside_32_bites_as_small_big_int() {
333    let expected = vec![131, 110, 4, 1, 1, 0, 0, 128];
334
335    let input = num_bigint::BigInt::from(i32::MIN as i64 - 1);
336
337    assert_eq!(expected, encode_big_integer(&input));
338}
339
340#[test]
341fn encode_small_big_int() {
342    // :erlang.term_to_binary(24**120)
343    let expected = vec![
344        131, 110, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
345        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 68, 238, 176, 235, 252,
346        240, 96, 176, 91, 142, 219, 66, 30, 177, 137, 199, 21, 191, 153, 182, 169, 73, 73,
347    ];
348
349    let input = num_bigint::BigInt::from(24).pow(120);
350
351    assert_eq!(expected, encode_big_integer(&input));
352}
353
354#[test]
355fn encode_negative_small_big_int() {
356    // :erlang.term_to_binary(-17**121)
357    let expected = vec![
358        131, 110, 62, 1, 145, 35, 189, 92, 121, 166, 54, 134, 249, 187, 212, 168, 99, 15, 199, 18,
359        199, 144, 202, 125, 24, 74, 178, 7, 108, 123, 248, 46, 241, 16, 48, 69, 1, 158, 117, 115,
360        239, 213, 166, 221, 100, 3, 60, 67, 137, 0, 113, 26, 119, 247, 227, 213, 91, 112, 34, 59,
361        186, 211, 12, 168, 222, 95,
362    ];
363
364    let input = num_bigint::BigInt::from(-17).pow(121);
365
366    assert_eq!(expected, encode_big_integer(&input));
367}
368
369#[test]
370fn encode_large_big_int() {
371    // :erlang.term_to_binary(5**923)
372    let expected = vec![
373        131, 111, 0, 0, 1, 12, 0, 157, 49, 35, 72, 82, 113, 71, 89, 143, 96, 245, 181, 222, 60,
374        192, 44, 126, 212, 89, 42, 70, 17, 126, 228, 141, 27, 155, 90, 226, 45, 64, 172, 156, 24,
375        197, 15, 30, 187, 15, 9, 134, 118, 177, 56, 98, 1, 252, 238, 113, 38, 174, 187, 181, 161,
376        128, 55, 122, 131, 27, 44, 224, 26, 96, 20, 60, 68, 84, 188, 139, 50, 27, 35, 46, 111, 179,
377        103, 3, 199, 16, 76, 202, 27, 108, 124, 189, 232, 63, 190, 120, 107, 231, 233, 67, 46, 164,
378        146, 45, 0, 180, 109, 22, 20, 201, 153, 9, 199, 7, 75, 91, 29, 48, 143, 191, 229, 182, 108,
379        161, 177, 245, 218, 54, 70, 12, 89, 196, 140, 138, 73, 115, 163, 249, 101, 13, 116, 117,
380        122, 72, 14, 71, 112, 6, 243, 124, 189, 51, 36, 199, 143, 80, 129, 8, 175, 54, 95, 104, 6,
381        40, 35, 244, 36, 219, 112, 129, 114, 96, 207, 37, 61, 113, 250, 82, 185, 101, 176, 68, 250,
382        128, 104, 151, 141, 54, 167, 30, 231, 244, 173, 120, 162, 209, 54, 193, 170, 19, 160, 192,
383        6, 233, 134, 70, 73, 142, 77, 174, 157, 177, 249, 210, 65, 164, 1, 27, 205, 204, 128, 251,
384        195, 234, 183, 185, 159, 191, 32, 252, 61, 28, 157, 38, 61, 130, 198, 248, 203, 196, 150,
385        186, 42, 43, 70, 136, 200, 78, 114, 229, 221, 198, 252, 187, 38, 162, 107, 52, 143, 177,
386        133, 185, 168, 30, 64, 0, 151, 20, 186, 82, 147, 226, 1, 2, 141,
387    ];
388
389    let input = num_bigint::BigInt::from(5).pow(923);
390
391    assert_eq!(expected, encode_big_integer(&input));
392}
393
394#[test]
395fn encode_negative_large_big_int() {
396    // :erlang.term_to_binary(-17**613)
397    let expected = vec![
398        131, 111, 0, 0, 1, 58, 1, 81, 128, 217, 64, 63, 89, 203, 140, 179, 117, 112, 210, 237, 68,
399        55, 214, 150, 63, 212, 77, 220, 75, 154, 120, 104, 18, 185, 178, 140, 7, 210, 84, 65, 183,
400        69, 128, 159, 165, 220, 21, 229, 65, 80, 122, 240, 162, 174, 250, 62, 222, 203, 58, 15,
401        215, 204, 106, 9, 213, 233, 208, 173, 124, 143, 108, 209, 19, 246, 224, 143, 58, 151, 72,
402        57, 203, 232, 159, 92, 71, 8, 128, 138, 187, 209, 239, 209, 189, 91, 50, 55, 3, 226, 214,
403        68, 115, 187, 151, 51, 139, 199, 133, 72, 135, 158, 46, 43, 168, 141, 235, 151, 168, 127,
404        2, 17, 73, 195, 85, 131, 34, 150, 45, 210, 55, 18, 192, 113, 207, 229, 131, 213, 56, 48,
405        60, 112, 76, 231, 109, 95, 46, 73, 56, 133, 2, 78, 96, 124, 119, 255, 5, 70, 120, 18, 146,
406        6, 102, 190, 157, 134, 72, 125, 98, 88, 182, 38, 21, 13, 165, 135, 45, 143, 43, 121, 101,
407        213, 130, 203, 180, 216, 230, 52, 163, 168, 125, 130, 100, 246, 179, 75, 211, 165, 66, 252,
408        232, 223, 119, 44, 105, 62, 1, 100, 61, 132, 185, 114, 75, 234, 116, 186, 208, 227, 77, 81,
409        18, 76, 125, 131, 116, 70, 180, 112, 76, 46, 36, 44, 243, 131, 190, 143, 166, 93, 72, 55,
410        1, 92, 19, 242, 248, 90, 209, 160, 223, 191, 15, 167, 89, 34, 45, 252, 219, 235, 190, 232,
411        32, 144, 232, 82, 173, 238, 213, 14, 157, 168, 162, 122, 24, 114, 192, 77, 18, 167, 147,
412        136, 239, 98, 85, 107, 86, 161, 156, 221, 20, 86, 1, 183, 233, 166, 236, 96, 181, 90, 197,
413        147, 189, 201, 71, 78, 206, 232, 115, 109, 222, 150, 213, 195, 164, 66, 123, 47, 151, 111,
414        193, 165, 1, 16, 3,
415    ];
416
417    let input = num_bigint::BigInt::from(-17).pow(613);
418
419    assert_eq!(expected, encode_big_integer(&input));
420}