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  }