mysql_common/value/convert/
bigint.rs
1use std::convert::TryFrom;
12
13use num_bigint::{BigInt, BigUint};
14use num_traits::{FromPrimitive, ToPrimitive};
15
16use super::{FromValue, FromValueError, ParseIr, Value};
17
18impl TryFrom<Value> for ParseIr<BigInt> {
19 type Error = FromValueError;
20
21 fn try_from(v: Value) -> Result<Self, Self::Error> {
22 match v {
23 Value::Int(x) => Ok(ParseIr(x.into(), v)),
24 Value::UInt(x) => Ok(ParseIr(x.into(), v)),
25 Value::Bytes(ref bytes) => match BigInt::parse_bytes(bytes, 10) {
26 Some(x) => Ok(ParseIr(x, v)),
27 None => Err(FromValueError(v)),
28 },
29 _ => Err(FromValueError(v)),
30 }
31 }
32}
33
34impl From<ParseIr<BigInt>> for BigInt {
35 fn from(value: ParseIr<BigInt>) -> Self {
36 value.commit()
37 }
38}
39
40impl From<ParseIr<BigInt>> for Value {
41 fn from(value: ParseIr<BigInt>) -> Self {
42 value.rollback()
43 }
44}
45
46impl FromValue for BigInt {
47 type Intermediate = ParseIr<BigInt>;
48}
49
50impl From<BigInt> for Value {
51 fn from(x: BigInt) -> Value {
52 if let Some(x) = x.to_i64() {
53 Value::Int(x)
54 } else if let Some(x) = x.to_u64() {
55 Value::UInt(x)
56 } else {
57 Value::Bytes(x.to_string().into())
58 }
59 }
60}
61
62impl TryFrom<Value> for ParseIr<BigUint> {
63 type Error = FromValueError;
64
65 fn try_from(v: Value) -> Result<Self, Self::Error> {
66 match v {
67 Value::Int(x) => {
68 if let Some(x) = BigUint::from_i64(x) {
69 Ok(ParseIr(x, v))
70 } else {
71 Err(FromValueError(v))
72 }
73 }
74 Value::UInt(x) => Ok(ParseIr(x.into(), v)),
75 Value::Bytes(ref bytes) => match BigUint::parse_bytes(bytes, 10) {
76 Some(x) => Ok(ParseIr(x, v)),
77 None => Err(FromValueError(v)),
78 },
79 _ => Err(FromValueError(v)),
80 }
81 }
82}
83
84impl From<ParseIr<BigUint>> for BigUint {
85 fn from(value: ParseIr<BigUint>) -> Self {
86 value.commit()
87 }
88}
89
90impl From<ParseIr<BigUint>> for Value {
91 fn from(value: ParseIr<BigUint>) -> Self {
92 value.rollback()
93 }
94}
95
96impl FromValue for BigUint {
97 type Intermediate = ParseIr<BigUint>;
98}
99
100impl From<BigUint> for Value {
101 fn from(x: BigUint) -> Value {
102 if let Some(x) = x.to_u64() {
103 Value::UInt(x)
104 } else {
105 Value::Bytes(x.to_string().into())
106 }
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use num_bigint::{BigInt, BigUint};
113 use proptest::prelude::*;
114
115 use crate::value::{convert::from_value, Value};
116
117 proptest! {
118 #[test]
119 fn big_int_roundtrip(
120 bytes_pos in r"[1-9][0-9]{31}",
121 bytes_neg in r"-[1-9][0-9]{31}",
122 uint in (i64::max_value() as u64 + 1)..u64::max_value(),
123 int: i64,
124 ) {
125 let val_bytes_pos = Value::Bytes(bytes_pos.as_bytes().into());
126 let val_bytes_neg = Value::Bytes(bytes_neg.as_bytes().into());
127 let val_uint = Value::UInt(uint);
128 let val_int = Value::Int(int);
129
130 assert_eq!(Value::from(from_value::<BigInt>(val_bytes_pos.clone())), val_bytes_pos);
131 assert_eq!(Value::from(from_value::<BigInt>(val_bytes_neg.clone())), val_bytes_neg);
132 assert_eq!(Value::from(from_value::<BigInt>(val_uint.clone())), val_uint);
133 assert_eq!(Value::from(from_value::<BigInt>(val_int.clone())), val_int);
134 }
135
136 #[test]
137 fn big_uint_roundtrip(
138 bytes in r"[1-9][0-9]{31}",
139 uint: u64,
140 int in 0i64..i64::max_value(),
141 ) {
142 let val_bytes = Value::Bytes(bytes.as_bytes().into());
143 let val_uint = Value::UInt(uint);
144 let val_int = Value::Int(int);
145
146 assert_eq!(Value::from(from_value::<BigUint>(val_bytes.clone())), val_bytes);
147 assert_eq!(Value::from(from_value::<BigUint>(val_uint.clone())), val_uint);
148 assert_eq!(Value::from(from_value::<BigUint>(val_int)), Value::UInt(int as u64));
149 }
150 }
151}