mysql_common/value/convert/
bigint.rs

1// Copyright (c) 2017 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9//! This module implements conversion from/to `Value` for `BigInt` and `BigUint` types.
10
11use 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}