mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
368 lines
7.7 KiB
Go
368 lines
7.7 KiB
Go
package gou
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"math"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Coerce types (string,int,int64, float, []byte) into String type
|
|
func CoerceString(v interface{}) (string, error) {
|
|
switch val := v.(type) {
|
|
case string:
|
|
if val == "null" || val == "NULL" {
|
|
return "", nil
|
|
}
|
|
return val, nil
|
|
case int:
|
|
return strconv.Itoa(val), nil
|
|
case int32:
|
|
return strconv.FormatInt(int64(val), 10), nil
|
|
case int64:
|
|
return strconv.FormatInt(val, 10), nil
|
|
case uint32:
|
|
return strconv.FormatUint(uint64(val), 10), nil
|
|
case uint64:
|
|
return strconv.FormatUint(val, 10), nil
|
|
case float32:
|
|
return strconv.FormatFloat(float64(val), 'f', -1, 32), nil
|
|
case float64:
|
|
return strconv.FormatFloat(val, 'f', -1, 64), nil
|
|
case bool:
|
|
if val {
|
|
return "true", nil
|
|
}
|
|
return "false", nil
|
|
case []byte:
|
|
if string(val) == "null" || string(val) == "NULL" {
|
|
return "", nil
|
|
}
|
|
return string(val), nil
|
|
case json.RawMessage:
|
|
if string(val) == "null" || string(val) == "NULL" {
|
|
return "", nil
|
|
}
|
|
return string(val), nil
|
|
}
|
|
return "", fmt.Errorf("Could not coerce to string: %v", v)
|
|
}
|
|
|
|
// Coerce type to string, returning zero length string if error or nil
|
|
func CoerceStringShort(v interface{}) string {
|
|
val, _ := CoerceString(v)
|
|
return val
|
|
}
|
|
|
|
// CoerceStrings Coerce type to strings, will split on comma by default.
|
|
func CoerceStrings(v interface{}) []string {
|
|
switch val := v.(type) {
|
|
case string:
|
|
if val == "" {
|
|
return nil
|
|
}
|
|
return strings.Split(val, ",")
|
|
case []string:
|
|
return val
|
|
case []interface{}:
|
|
sva := make([]string, 0)
|
|
for _, av := range val {
|
|
switch aval := av.(type) {
|
|
case string:
|
|
sva = append(sva, aval)
|
|
default:
|
|
sv, err := CoerceString(av)
|
|
if err == nil && sv != "" {
|
|
sva = append(sva, sv)
|
|
}
|
|
}
|
|
}
|
|
return sva
|
|
}
|
|
return []string{CoerceStringShort(v)}
|
|
}
|
|
|
|
func CoerceFloats(v interface{}) []float64 {
|
|
switch val := v.(type) {
|
|
case float64:
|
|
return []float64{val}
|
|
case []string:
|
|
fa := make([]float64, 0)
|
|
for _, av := range val {
|
|
f, err := CoerceFloat(av)
|
|
if err == nil && !math.IsNaN(f) {
|
|
fa = append(fa, f)
|
|
}
|
|
}
|
|
return fa
|
|
case []interface{}:
|
|
fa := make([]float64, 0)
|
|
for _, av := range val {
|
|
switch aval := av.(type) {
|
|
case float64:
|
|
fa = append(fa, aval)
|
|
default:
|
|
f, err := CoerceFloat(av)
|
|
if err == nil && !math.IsNaN(f) {
|
|
fa = append(fa, f)
|
|
}
|
|
}
|
|
}
|
|
return fa
|
|
}
|
|
fv, err := CoerceFloat(v)
|
|
if err == nil {
|
|
return []float64{fv}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func CoerceFloat(v interface{}) (float64, error) {
|
|
switch val := v.(type) {
|
|
case int:
|
|
return float64(val), nil
|
|
case int32:
|
|
return float64(val), nil
|
|
case int64:
|
|
return float64(val), nil
|
|
case uint32:
|
|
return float64(val), nil
|
|
case uint64:
|
|
return float64(val), nil
|
|
case float64:
|
|
return val, nil
|
|
case string:
|
|
if len(val) > 0 {
|
|
if iv, err := strconv.ParseFloat(val, 64); err == nil {
|
|
return iv, nil
|
|
}
|
|
}
|
|
case []byte:
|
|
if len(val) > 0 {
|
|
if iv, err := strconv.ParseFloat(string(val), 64); err == nil {
|
|
return iv, nil
|
|
}
|
|
}
|
|
case json.RawMessage:
|
|
if len(val) > 0 {
|
|
if iv, err := strconv.ParseFloat(string(val), 64); err == nil {
|
|
return iv, nil
|
|
}
|
|
}
|
|
case nil:
|
|
return math.NaN(), nil
|
|
}
|
|
return 0, fmt.Errorf("Could not Coerce Value: %v", v)
|
|
}
|
|
func CoerceFloatShort(v interface{}) float64 {
|
|
val, _ := CoerceFloat(v)
|
|
return val
|
|
}
|
|
|
|
func CoerceInt64(v interface{}) (int64, error) {
|
|
val, ok := valToInt64(v)
|
|
if ok {
|
|
return val, nil
|
|
}
|
|
return 0, fmt.Errorf("Could not coerce to int64: %v", v)
|
|
}
|
|
func CoerceInt64Short(v interface{}) int64 {
|
|
val, ok := valToInt64(v)
|
|
if ok {
|
|
return val
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func CoerceInt(v interface{}) (int, error) {
|
|
val, ok := valToInt(v)
|
|
if ok {
|
|
return val, nil
|
|
}
|
|
return 0, fmt.Errorf("Could not coerce to int64: %v", v)
|
|
}
|
|
func CoerceIntShort(v interface{}) int {
|
|
val, ok := valToInt(v)
|
|
if ok {
|
|
return val
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func CoerceInts(v interface{}) []int {
|
|
switch val := v.(type) {
|
|
case []string:
|
|
iva := make([]int, 0)
|
|
for _, av := range val {
|
|
avAsInt, ok := valToInt(av)
|
|
if ok {
|
|
iva = append(iva, avAsInt)
|
|
}
|
|
}
|
|
return iva
|
|
case []interface{}:
|
|
iva := make([]int, 0)
|
|
for _, av := range val {
|
|
avAsInt, ok := valToInt(av)
|
|
if ok {
|
|
iva = append(iva, avAsInt)
|
|
}
|
|
}
|
|
return iva
|
|
}
|
|
return []int{CoerceIntShort(v)}
|
|
}
|
|
|
|
// Coerce a val(interface{}) into a Uint64
|
|
func CoerceUint(v interface{}) (uint64, error) {
|
|
u64, ok := valToUint64(v)
|
|
if !ok {
|
|
return 0, fmt.Errorf("Could not Coerce %v", v)
|
|
}
|
|
return u64, nil
|
|
}
|
|
|
|
// Coerce a Val(interface{}) into Uint64
|
|
func CoerceUintShort(v interface{}) uint64 {
|
|
val, _ := CoerceUint(v)
|
|
return val
|
|
}
|
|
|
|
// Given any numeric type (float*, int*, uint*, string) return an int. Returns false if it would
|
|
// overflow or if the the argument is not numeric.
|
|
func valToInt(i interface{}) (int, bool) {
|
|
i64, ok := valToInt64(i)
|
|
if !ok {
|
|
return -1, false
|
|
}
|
|
if i64 > MaxInt || i64 < MinInt {
|
|
return -1, false
|
|
}
|
|
return int(i64), true
|
|
}
|
|
|
|
// Given any simple type (float*, int*, uint*, string, []byte, json.RawMessage) return an int64.
|
|
// Returns false if it would overflow or if the the argument is not numeric.
|
|
func valToInt64(i interface{}) (int64, bool) {
|
|
switch x := i.(type) {
|
|
case float32:
|
|
return int64(x), true
|
|
case float64:
|
|
return int64(x), true
|
|
case uint8:
|
|
return int64(x), true
|
|
case uint16:
|
|
return int64(x), true
|
|
case uint32:
|
|
return int64(x), true
|
|
case uint64:
|
|
if x > math.MaxInt64 {
|
|
return 0, false
|
|
}
|
|
return int64(x), true
|
|
case int8:
|
|
return int64(x), true
|
|
case int16:
|
|
return int64(x), true
|
|
case int32:
|
|
return int64(x), true
|
|
case int64:
|
|
return int64(x), true
|
|
case int:
|
|
return int64(x), true
|
|
case uint:
|
|
if uint64(x) > math.MaxInt64 {
|
|
return 0, false
|
|
}
|
|
return int64(x), true
|
|
case string:
|
|
if len(x) > 0 {
|
|
if iv, err := strconv.ParseInt(x, 10, 64); err == nil {
|
|
return iv, true
|
|
}
|
|
if iv, err := strconv.ParseFloat(x, 64); err == nil {
|
|
return valToInt64(iv)
|
|
}
|
|
}
|
|
case []byte:
|
|
if len(x) > 0 {
|
|
if iv, err := strconv.ParseInt(string(x), 10, 64); err == nil {
|
|
return iv, true
|
|
}
|
|
if iv, err := strconv.ParseFloat(string(x), 64); err == nil {
|
|
return valToInt64(iv)
|
|
}
|
|
}
|
|
case json.RawMessage:
|
|
if len(x) > 0 {
|
|
if iv, err := strconv.ParseInt(string(x), 10, 64); err == nil {
|
|
return iv, true
|
|
}
|
|
if iv, err := strconv.ParseFloat(string(x), 64); err == nil {
|
|
return valToInt64(iv)
|
|
}
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// Given any simple type (float*, int*, uint*, string, []byte, json.RawMessage) return an int64.
|
|
// Returns false if it would overflow or if the the argument is not numeric.
|
|
func valToUint64(i interface{}) (uint64, bool) {
|
|
switch x := i.(type) {
|
|
case float32:
|
|
return uint64(x), true
|
|
case float64:
|
|
return uint64(x), true
|
|
case uint8:
|
|
return uint64(x), true
|
|
case uint16:
|
|
return uint64(x), true
|
|
case uint32:
|
|
return uint64(x), true
|
|
case uint64:
|
|
return x, true
|
|
case int8:
|
|
return uint64(x), true
|
|
case int16:
|
|
return uint64(x), true
|
|
case int32:
|
|
return uint64(x), true
|
|
case int64:
|
|
return uint64(x), true
|
|
case int:
|
|
return uint64(x), true
|
|
case uint:
|
|
return uint64(x), true
|
|
case string:
|
|
if len(x) > 0 {
|
|
if uiv, err := strconv.ParseUint(x, 10, 64); err == nil {
|
|
return uiv, true
|
|
}
|
|
if fv, err := strconv.ParseFloat(x, 64); err == nil {
|
|
return uint64(fv), true
|
|
}
|
|
}
|
|
case []byte:
|
|
if len(x) > 0 {
|
|
if uiv, err := strconv.ParseUint(string(x), 10, 64); err == nil {
|
|
return uiv, true
|
|
}
|
|
if fv, err := strconv.ParseFloat(string(x), 64); err == nil {
|
|
return uint64(fv), true
|
|
}
|
|
}
|
|
case json.RawMessage:
|
|
if len(x) > 0 {
|
|
if uiv, err := strconv.ParseUint(string(x), 10, 64); err == nil {
|
|
return uiv, true
|
|
}
|
|
if fv, err := strconv.ParseFloat(string(x), 64); err == nil {
|
|
return uint64(fv), true
|
|
}
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|