package jsoniter import ( "fmt" "reflect" "strconv" ) // Any API is for maximum flexibility type Any struct { val interface{} Error error LastAccessed interface{} } // MakeAny creates Any instance func MakeAny(val interface{}) *Any { return &Any{val, nil, nil} } // Get extracts a json object from Any func (any *Any) Get(keys ...interface{}) interface{} { ret, err := getPath(any.val, keys...) any.LastAccessed = ret if err != nil { any.Error = err return "" } return ret } // GetValueType gets type of a value func (any *Any) GetValueType(keys ...interface{}) ValueType { ret, err := getPath(any.val, keys...) any.LastAccessed = ret if err != nil { any.Error = err return Invalid } switch reflect.TypeOf(ret).Kind() { case reflect.Uint8: return Number case reflect.Int8: return Number case reflect.Uint16: return Number case reflect.Int16: return Number case reflect.Uint32: return Number case reflect.Int32: return Number case reflect.Uint64: return Number case reflect.Int64: return Number case reflect.Int: return Number case reflect.Uint: return Number case reflect.Float32: return Number case reflect.Float64: return Number case reflect.String: return String case reflect.Bool: return Bool case reflect.Array: return Array case reflect.Struct: return Object default: return Invalid } } // ToString converts a json object to string func (any *Any) ToString(keys ...interface{}) string { ret, err := getPath(any.val, keys...) any.LastAccessed = ret if err != nil { any.Error = err return "" } switch ret := ret.(type) { case uint8: return strconv.FormatInt(int64(ret), 10) case int8: return strconv.FormatInt(int64(ret), 10) case uint16: return strconv.FormatInt(int64(ret), 10) case int16: return strconv.FormatInt(int64(ret), 10) case uint32: return strconv.FormatInt(int64(ret), 10) case int32: return strconv.FormatInt(int64(ret), 10) case uint64: return strconv.FormatUint(uint64(ret), 10) case int64: return strconv.FormatInt(int64(ret), 10) case int: return strconv.FormatInt(int64(ret), 10) case uint: return strconv.FormatInt(int64(ret), 10) case float32: return strconv.FormatFloat(float64(ret), 'E', -1, 32) case float64: return strconv.FormatFloat(ret, 'E', -1, 64) case string: return ret default: return fmt.Sprintf("%v", ret) } } // ToUint8 converts a json object to Uint8 func (any *Any) ToUint8(keys ...interface{}) uint8 { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return uint8(ret) } // ToInt8 converts a json object to Int8 func (any *Any) ToInt8(keys ...interface{}) int8 { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return int8(ret) } // ToUint16 converts a json object to Uint16 func (any *Any) ToUint16(keys ...interface{}) uint16 { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return uint16(ret) } // ToInt16 converts a json object to Int16 func (any *Any) ToInt16(keys ...interface{}) int16 { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return int16(ret) } // ToUint32 converts a json object to Uint32 func (any *Any) ToUint32(keys ...interface{}) uint32 { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return uint32(ret) } // ToInt32 converts a json object to Int32 func (any *Any) ToInt32(keys ...interface{}) int32 { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return int32(ret) } // ToUint64 converts a json object to Uint64 func (any *Any) ToUint64(keys ...interface{}) uint64 { ret, err := getPathAsUint64(any, keys...) if err != nil { any.Error = err return 0 } return uint64(ret) } // ToInt64 converts a json object to Int64 func (any *Any) ToInt64(keys ...interface{}) int64 { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return int64(ret) } // ToInt converts a json object to Int func (any *Any) ToInt(keys ...interface{}) int { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return int(ret) } // ToUint converts a json object to Uint func (any *Any) ToUint(keys ...interface{}) uint { ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0 } return uint(ret) } // ToFloat32 converts a json object to Float32 func (any *Any) ToFloat32(keys ...interface{}) float32 { ret, err := getPathAsFloat64(any, keys...) if err != nil { any.Error = err return 0 } return float32(ret) } // ToFloat64 converts a json object to Float64 func (any *Any) ToFloat64(keys ...interface{}) float64 { ret, err := getPathAsFloat64(any, keys...) if err != nil { any.Error = err return 0 } return ret } // ToBool converts a json object to Bool func (any *Any) ToBool(keys ...interface{}) bool { ret, err := getPath(any.val, keys...) any.LastAccessed = ret if err != nil { any.Error = err return false } typedRet, ok := ret.(bool) if !ok { any.Error = fmt.Errorf("%v is not bool", ret) return false } return typedRet } // IsNil judges whether a json object is nil func (any *Any) IsNil(keys ...interface{}) bool { ret, err := getPath(any.val, keys...) any.LastAccessed = ret if err != nil { any.Error = err return false } return reflect.ValueOf(ret).IsNil() } func getPathAsInt64(any *Any, keys ...interface{}) (int64, error) { ret, err := getPath(any.val, keys...) any.LastAccessed = ret if err != nil { any.Error = err return 0, err } switch ret := ret.(type) { case uint8: return int64(ret), nil case int8: return int64(ret), nil case uint16: return int64(ret), nil case int16: return int64(ret), nil case uint32: return int64(ret), nil case int32: return int64(ret), nil case uint64: return int64(ret), nil case int64: return int64(ret), nil case int: return int64(ret), nil case uint: return int64(ret), nil case float32: return int64(ret), nil case float64: return int64(ret), nil case string: intVal, err := strconv.ParseInt(ret, 10, 64) if err != nil { return 0, err } return intVal, nil default: return 0, fmt.Errorf("%v is not number", ret) } } func getPathAsUint64(any *Any, keys ...interface{}) (uint64, error) { ret, err := getPath(any.val, keys...) any.LastAccessed = ret if err != nil { any.Error = err return 0, err } switch ret := ret.(type) { case uint8: return uint64(ret), nil case int8: return uint64(ret), nil case uint16: return uint64(ret), nil case int16: return uint64(ret), nil case uint32: return uint64(ret), nil case int32: return uint64(ret), nil case uint64: return uint64(ret), nil case int64: return uint64(ret), nil case int: return uint64(ret), nil case uint: return uint64(ret), nil case float32: return uint64(ret), nil case float64: return uint64(ret), nil case string: intVal, err := strconv.ParseUint(ret, 10, 64) if err != nil { return 0, err } return intVal, nil default: return 0, fmt.Errorf("%v is not number", ret) } } func getPathAsFloat64(any *Any, keys ...interface{}) (float64, error) { ret, err := getPath(any.val, keys...) any.LastAccessed = ret if err != nil { any.Error = err return 0, err } switch ret := ret.(type) { case uint8: return float64(ret), nil case int8: return float64(ret), nil case uint16: return float64(ret), nil case int16: return float64(ret), nil case uint32: return float64(ret), nil case int32: return float64(ret), nil case uint64: return float64(ret), nil case int64: return float64(ret), nil case int: return float64(ret), nil case uint: return float64(ret), nil case float32: return float64(ret), nil case float64: return float64(ret), nil case string: floatVal, err := strconv.ParseFloat(ret, 64) if err != nil { return 0, err } return floatVal, nil default: return 0, fmt.Errorf("%v is not number", ret) } } func getPath(val interface{}, keys ...interface{}) (interface{}, error) { if len(keys) == 0 { return val, nil } switch key := keys[0].(type) { case string: nextVal, err := getFromMap(val, key) if err != nil { return nil, err } nextKeys := make([]interface{}, len(keys)-1) copy(nextKeys, keys[1:]) return getPath(nextVal, nextKeys...) case int: nextVal, err := getFromArray(val, key) if err != nil { return nil, err } nextKeys := make([]interface{}, len(keys)-1) copy(nextKeys, keys[1:]) return getPath(nextVal, nextKeys...) default: return nil, fmt.Errorf("%v is not string or int", keys[0]) } } func getFromMap(val interface{}, key string) (interface{}, error) { mapVal, ok := val.(map[string]interface{}) if !ok { return nil, fmt.Errorf("%v is not map[string]interface{}", val) } ret, found := mapVal[key] if !found { return nil, fmt.Errorf("%v not found in %v", key, mapVal) } return ret, nil } func getFromArray(val interface{}, key int) (interface{}, error) { arrayVal, ok := val.([]interface{}) if !ok { return nil, fmt.Errorf("%v is not []interface{}", val) } if key >= len(arrayVal) { return nil, fmt.Errorf("%v exceed %v", key, arrayVal) } if key < 0 { return nil, fmt.Errorf("%v exceed %v", key, arrayVal) } return arrayVal[key], nil }