1use rug::Integer;
2use rug::integer::Order;
3
4use crate::{
5 Error, Result, Tag, Value,
6 integer::IntegerBytes,
7 util::{trim_leading_zeros, u64_from_slice},
8};
9
10impl From<Integer> for Value {
15 fn from(value: Integer) -> Self {
20 from_rug_integer(&value)
21 }
22}
23
24impl From<&Integer> for Value {
25 fn from(value: &Integer) -> Self {
26 from_rug_integer(value)
27 }
28}
29
30fn from_rug_integer(value: &Integer) -> Value {
31 use std::cmp::Ordering;
32
33 match value.cmp0() {
34 Ordering::Equal => Value::Unsigned(0),
35 Ordering::Greater => {
36 let bytes: Vec<u8> = value.to_digits(Order::MsfBe);
37 let trimmed = trim_leading_zeros(&bytes);
38
39 if let Ok(number) = u64_from_slice(trimmed) {
40 Value::Unsigned(number)
41 } else if bytes.len() == trimmed.len() {
42 Value::tag(Tag::POS_BIG_INT, bytes)
43 } else {
44 Value::tag(Tag::POS_BIG_INT, trimmed)
45 }
46 }
47 Ordering::Less => {
48 let magnitude = Integer::from(-value);
50 let payload = magnitude - 1_u32;
51 let bytes: Vec<u8> = payload.to_digits(Order::MsfBe);
52 let trimmed = trim_leading_zeros(&bytes);
53
54 if let Ok(number) = u64_from_slice(trimmed) {
55 Value::Negative(number)
56 } else if bytes.len() == trimmed.len() {
57 Value::tag(Tag::NEG_BIG_INT, bytes)
58 } else {
59 Value::tag(Tag::NEG_BIG_INT, trimmed)
60 }
61 }
62 }
63}
64
65impl TryFrom<Value> for Integer {
70 type Error = Error;
71
72 fn try_from(value: Value) -> Result<Self> {
76 to_rug_integer(&value)
77 }
78}
79
80impl TryFrom<&Value> for Integer {
81 type Error = Error;
82
83 fn try_from(value: &Value) -> Result<Self> {
84 to_rug_integer(value)
85 }
86}
87
88fn to_rug_integer(value: &Value) -> Result<Integer> {
89 match value.as_integer_bytes()? {
90 IntegerBytes::UnsignedOwned(bytes) => Ok(Integer::from(u64::from_be_bytes(bytes))),
91 IntegerBytes::NegativeOwned(bytes) => Ok(Integer::from(!u64::from_be_bytes(bytes) as i64)),
92 IntegerBytes::UnsignedBorrowed(bytes) => Ok(Integer::from_digits(bytes, Order::MsfBe)),
93 IntegerBytes::NegativeBorrowed(bytes) => {
94 let payload = Integer::from_digits(bytes, Order::MsfBe);
96 Ok(-(payload + 1_u32))
97 }
98 }
99}
100
101#[cfg(test)]
106mod tests {
107 use super::*;
108 use crate::DataType;
109
110 fn roundtrip(n: Integer) -> Integer {
111 let encoded = Value::from(&n).encode();
112 let decoded = Value::decode(encoded).unwrap();
113 Integer::try_from(decoded).unwrap()
114 }
115
116 #[test]
119 fn zero() {
120 assert_eq!(roundtrip(Integer::ZERO), Integer::ZERO);
121 }
122
123 #[test]
124 fn small_positive() {
125 let n = Integer::from(42);
126 assert_eq!(roundtrip(n.clone()), n);
127 }
128
129 #[test]
130 fn u64_max() {
131 let n = Integer::from(u64::MAX);
132 let v = Value::from(&n);
133 assert!(matches!(v, Value::Unsigned(_)));
134 assert_eq!(Integer::try_from(v).unwrap(), n);
135 }
136
137 #[test]
138 fn u128_max() {
139 let n = Integer::from(u128::MAX);
140 let v = Value::from(&n);
141 assert!(matches!(&v, Value::Tag(2, _)));
142 assert_eq!(Integer::try_from(v).unwrap(), n);
143 }
144
145 #[test]
146 fn from_u128_roundtrip() {
147 for x in [0_u128, 1, 42, u64::MAX as u128, u64::MAX as u128 + 1, u128::MAX] {
148 let expected = Integer::from(x);
149 let via_value = Value::from(x);
150 assert_eq!(Integer::try_from(via_value).unwrap(), expected, "u128={x}");
151 }
152 }
153
154 #[test]
157 fn negative_one() {
158 let n = Integer::from(-1);
159 assert_eq!(roundtrip(n.clone()), n);
160 }
161
162 #[test]
163 fn i64_min() {
164 let n = Integer::from(i64::MIN);
165 assert_eq!(roundtrip(n.clone()), n);
166 }
167
168 #[test]
169 fn i128_min() {
170 let n = Integer::from(i128::MIN);
171 let v = Value::from(&n);
172 assert!(matches!(&v, Value::Tag(3, _)));
173 assert_eq!(Integer::try_from(v).unwrap(), n);
174 }
175
176 #[test]
177 fn i128_max() {
178 let n = Integer::from(i128::MAX);
179 let v = Value::from(&n);
180 assert_eq!(Integer::try_from(v).unwrap(), n);
181 }
182
183 #[test]
184 fn from_i128_roundtrip() {
185 for x in [
186 0_i128,
187 1,
188 -1,
189 42,
190 -42,
191 i64::MIN as i128,
192 i64::MAX as i128,
193 i128::MIN,
194 i128::MAX,
195 ] {
196 let expected = Integer::from(x);
197 let via_value = Value::from(x);
198 assert_eq!(Integer::try_from(via_value).unwrap(), expected, "i128={x}");
199 }
200 }
201
202 #[test]
203 fn large_negative() {
204 let n = -Integer::from(u128::MAX);
206 let v = Value::from(&n);
207 assert!(matches!(&v, Value::Tag(3, _)));
208 assert_eq!(Integer::try_from(v).unwrap(), n);
209 }
210
211 #[test]
214 fn non_integer_errors() {
215 assert_eq!(
216 Integer::try_from(Value::from(0.5)),
217 Err(Error::IncompatibleType(DataType::Float16))
218 );
219 assert_eq!(
220 Integer::try_from(Value::null()),
221 Err(Error::IncompatibleType(DataType::Null))
222 );
223 }
224}