1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! Conversion implementations for from a thing into [AnyNumeric]
use core::ffi::CStr;
use core::str::FromStr;

use pg_sys::AsPgCStr;

use crate::numeric_support::call_numeric_func;
use crate::numeric_support::convert::{from_primitive_helper, FromPrimitiveFunc};
use crate::numeric_support::error::Error;
use crate::{pg_sys, AnyNumeric, IntoDatum, Numeric};

impl<const P: u32, const S: u32> From<Numeric<P, S>> for AnyNumeric {
    #[inline]
    fn from(n: Numeric<P, S>) -> Self {
        n.0
    }
}

macro_rules! anynumeric_from_signed {
    ($ty:ty, $as_:ty, $func:path) => {
        impl From<$ty> for AnyNumeric {
            #[inline]
            fn from(value: $ty) -> Self {
                call_numeric_func($func.into(), &[(value as $as_).into_datum()])
            }
        }
    };
}

macro_rules! anynumeric_from_oversized_primitive {
    ($ty:ty, $signed:ty) => {
        impl From<$ty> for AnyNumeric {
            #[inline]
            fn from(value: $ty) -> Self {
                match <$signed>::try_from(value) {
                    Ok(value) => AnyNumeric::from(value),
                    Err(_) => AnyNumeric::try_from(value.to_string().as_str()).unwrap(),
                }
            }
        }
    };
}

anynumeric_from_signed!(isize, i64, FromPrimitiveFunc::Int8Numeric);
anynumeric_from_signed!(i64, i64, FromPrimitiveFunc::Int8Numeric);
anynumeric_from_signed!(i32, i32, FromPrimitiveFunc::Int4Numeric);
anynumeric_from_signed!(i16, i16, FromPrimitiveFunc::Int2Numeric);
anynumeric_from_signed!(i8, i16, FromPrimitiveFunc::Int2Numeric);

anynumeric_from_oversized_primitive!(usize, i64);
anynumeric_from_oversized_primitive!(u64, i64);
anynumeric_from_oversized_primitive!(u32, i32);
anynumeric_from_oversized_primitive!(u16, i16);
anynumeric_from_oversized_primitive!(u8, i8);

anynumeric_from_oversized_primitive!(i128, i64);
anynumeric_from_oversized_primitive!(u128, i64);

macro_rules! anynumeric_from_float {
    ($ty:ty, $func:path) => {
        impl TryFrom<$ty> for AnyNumeric {
            type Error = Error;

            #[inline]
            fn try_from(value: $ty) -> Result<Self, Self::Error> {
                // these versions of Postgres can't represent +/-Infinity as a NUMERIC
                // so we run through a PgTryBuilder to ask Postgres to do the conversion which will
                // simply return the proper Error
                #[cfg(any(feature = "pg11", feature = "pg12", feature = "pg13"))]
                {
                    if value.is_infinite() {
                        return from_primitive_helper::<_, 0, 0>(value, $func).map(|n| n.into());
                    }
                }

                Ok(call_numeric_func($func.into(), &[value.into_datum()]))
            }
        }
    };
}

anynumeric_from_float!(f32, FromPrimitiveFunc::Float4Numeric);
anynumeric_from_float!(f64, FromPrimitiveFunc::Float8Numeric);

impl TryFrom<&CStr> for AnyNumeric {
    type Error = Error;

    #[inline]
    fn try_from(value: &CStr) -> Result<Self, Self::Error> {
        AnyNumeric::from_str(value.to_string_lossy().as_ref())
    }
}

impl TryFrom<&str> for AnyNumeric {
    type Error = Error;

    #[inline]
    fn try_from(value: &str) -> Result<Self, Self::Error> {
        AnyNumeric::from_str(value)
    }
}

impl FromStr for AnyNumeric {
    type Err = Error;

    #[inline]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        unsafe {
            let ptr = s.as_pg_cstr();
            let cstr = CStr::from_ptr(ptr);
            let numeric = from_primitive_helper::<_, 0, 0>(cstr, FromPrimitiveFunc::NumericIn)
                .map(|n| n.into());
            pg_sys::pfree(ptr.cast());
            numeric
        }
    }
}