Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
446 lines (418 sloc) 9.21 KB
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
}