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