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