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
96
97
98
99
100
101
102
103
use crate::*;
use crate::serialization::utils::read_nint;
impl Serialize for BigInt {
fn serialize<'se, W: Write>(
&self,
serializer: &'se mut Serializer<W>,
) -> cbor_event::Result<&'se mut Serializer<W>> {
let (sign, u64_digits) = self.0.to_u64_digits();
match u64_digits.len() {
0 => serializer.write_unsigned_integer(0),
// we use the uint/nint encodings to use a minimum of space
1 => match sign {
// uint
num_bigint::Sign::Plus | num_bigint::Sign::NoSign => {
serializer.write_unsigned_integer(*u64_digits.first().unwrap())
}
// nint
num_bigint::Sign::Minus => serializer
.write_negative_integer(-(*u64_digits.first().unwrap() as i128) as i64),
},
_ => {
// Small edge case: nint's minimum is -18446744073709551616 but in this bigint lib
// that takes 2 u64 bytes so we put that as a special case here:
if sign == num_bigint::Sign::Minus && u64_digits == vec![0, 1] {
serializer.write_negative_integer(-18446744073709551616i128 as i64)
} else {
let (sign, bytes) = self.0.to_bytes_be();
match sign {
// positive bigint
num_bigint::Sign::Plus | num_bigint::Sign::NoSign => {
serializer.write_tag(2u64)?;
write_bounded_bytes(serializer, &bytes)
}
// negative bigint
num_bigint::Sign::Minus => {
serializer.write_tag(3u64)?;
use std::ops::Neg;
// CBOR RFC defines this as the bytes of -n -1
let adjusted = self
.0
.clone()
.neg()
.checked_sub(&num_bigint::BigInt::from(1u32))
.unwrap()
.to_biguint()
.unwrap();
write_bounded_bytes(serializer, &adjusted.to_bytes_be())
}
}
}
}
}
}
}
impl Deserialize for BigInt {
fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
(|| -> Result<_, DeserializeError> {
match raw.cbor_type()? {
// bigint
CBORType::Tag => {
let tag = raw.tag()?;
let bytes = read_bounded_bytes(raw)?;
match tag {
// positive bigint
2 => Ok(Self(num_bigint::BigInt::from_bytes_be(
num_bigint::Sign::Plus,
&bytes,
))),
// negative bigint
3 => {
// CBOR RFC defines this as the bytes of -n -1
let initial =
num_bigint::BigInt::from_bytes_be(num_bigint::Sign::Plus, &bytes);
use std::ops::Neg;
let adjusted = initial
.checked_add(&num_bigint::BigInt::from(1u32))
.unwrap()
.neg();
Ok(Self(adjusted))
}
_ => {
return Err(DeserializeFailure::TagMismatch {
found: tag,
expected: 2,
}
.into());
}
}
}
// uint
CBORType::UnsignedInteger => {
Ok(Self(num_bigint::BigInt::from(raw.unsigned_integer()?)))
}
// nint
CBORType::NegativeInteger => Ok(Self(num_bigint::BigInt::from(read_nint(raw)?))),
_ => return Err(DeserializeFailure::NoVariantMatched.into()),
}
})()
.map_err(|e| e.annotate("BigInt"))
}
}