rustler/types/
big_int.rs

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