github.com/seeker-insurance/kit@v0.0.13/coerce/numeric.go (about) 1 //Package coerce provides c-style coercion for numeric types and strings, with additional guarantees for 2 //preservation of information. 3 package coerce 4 5 import ( 6 "math" 7 8 "github.com/seeker-insurance/kit/errorlib" 9 "github.com/seeker-insurance/kit/log" 10 ) 11 12 const ( 13 maxConsecutiveIntInDoublePrecision = 2 << 53 14 ErrOverflowInt64 errorlib.ErrorString = "overflow of int64" 15 ErrImpreciseConversion errorlib.ErrorString = "data loss on conversion to float64" 16 ErrWrongType errorlib.ErrorString = "could not coerce type" 17 ) 18 19 var ( 20 allowOverFlow = false 21 allowImpreciseConversion = true 22 warnOnImpreciseConversion = true 23 warnOnOverFlow = true 24 ) 25 26 func AllowOverflow(b bool) { allowOverFlow = b } 27 func AllowImpreciseConversion(b bool) { allowImpreciseConversion = b } 28 func WarnOnImpreciseConversion(b bool) { warnOnImpreciseConversion = b } 29 30 //Float64 converts a numeric type to a float64, if possible. 31 //Note for very large integers, this may lose information! 32 func Float64(v interface{}) (float64, error) { 33 switch v := v.(type) { 34 default: 35 return 0, ErrWrongType 36 case int: 37 if int(float64(v)) != v { 38 if warnOnImpreciseConversion { 39 log.Warn(ErrImpreciseConversion) 40 } 41 if !allowImpreciseConversion { 42 return float64(v), ErrImpreciseConversion 43 } 44 } 45 return float64(v), nil 46 47 case uint: 48 if uint(float64(v)) != v { 49 if warnOnImpreciseConversion { 50 log.Warn(ErrImpreciseConversion) 51 } 52 if !allowImpreciseConversion { 53 return float64(v), ErrImpreciseConversion 54 } 55 } 56 return float64(v), nil 57 58 case uint64: 59 if uint64(float64(v)) != v { 60 if warnOnImpreciseConversion { 61 log.Warn(ErrImpreciseConversion) 62 } 63 if !allowImpreciseConversion { 64 return float64(v), ErrImpreciseConversion 65 } 66 } 67 return float64(v), nil 68 69 case int64: 70 if int64(float64(v)) != v { 71 if warnOnImpreciseConversion { 72 log.Warn(ErrImpreciseConversion) 73 } 74 if !allowImpreciseConversion { 75 return float64(v), ErrImpreciseConversion 76 } 77 } 78 return float64(v), nil 79 80 case int8: 81 return float64(v), nil 82 case int16: 83 return float64(v), nil 84 case int32: 85 return float64(v), nil 86 case uint8: 87 return float64(v), nil 88 case uint16: 89 return float64(v), nil 90 case uint32: 91 return float64(v), nil 92 case float32: 93 return float64(v), nil 94 case float64: 95 return v, nil 96 } 97 } 98 99 //Int64 converts an integer type to an int64, if possible. Note that for very large unsigned ints, 100 //this may give an incorrect result! 101 func Int64(v interface{}) (int64, error) { 102 switch v := v.(type) { 103 default: 104 return 0, ErrWrongType 105 106 case uint: 107 if v > math.MaxInt64 { 108 if !allowOverFlow { 109 return int64(v), ErrOverflowInt64 110 } else if warnOnOverFlow { 111 log.Warn(ErrOverflowInt64) 112 } 113 } 114 return int64(v), nil 115 case uint64: 116 if v > math.MaxInt64 { 117 if !allowOverFlow { 118 return int64(v), ErrOverflowInt64 119 } else if warnOnOverFlow { 120 log.Warn(ErrOverflowInt64) 121 } 122 } 123 return int64(v), nil 124 case int: 125 return int64(v), nil 126 case int8: 127 return int64(v), nil 128 case int16: 129 return int64(v), nil 130 case int32: 131 return int64(v), nil 132 case int64: 133 return int64(v), nil 134 case uint8: 135 return int64(v), nil 136 case uint16: 137 return int64(v), nil 138 case uint32: 139 return int64(v), nil 140 } 141 }