summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/huandu/facebook/result.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/huandu/facebook/result.go')
-rw-r--r--Godeps/_workspace/src/github.com/huandu/facebook/result.go1097
1 files changed, 0 insertions, 1097 deletions
diff --git a/Godeps/_workspace/src/github.com/huandu/facebook/result.go b/Godeps/_workspace/src/github.com/huandu/facebook/result.go
deleted file mode 100644
index fd760be4e..000000000
--- a/Godeps/_workspace/src/github.com/huandu/facebook/result.go
+++ /dev/null
@@ -1,1097 +0,0 @@
-// A facebook graph api client in go.
-// https://github.com/huandu/facebook/
-//
-// Copyright 2012 - 2015, Huan Du
-// Licensed under the MIT license
-// https://github.com/huandu/facebook/blob/master/LICENSE
-
-package facebook
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "net/http"
- "reflect"
- "runtime"
- "strconv"
- "strings"
- "time"
-)
-
-// MakeResult makes a Result from facebook Graph API response.
-func MakeResult(jsonBytes []byte) (Result, error) {
- res := Result{}
- err := makeResult(jsonBytes, &res)
-
- if err != nil {
- return nil, err
- }
-
- // facebook may return an error
- return res, res.Err()
-}
-
-func makeResult(jsonBytes []byte, res interface{}) error {
- if bytes.Equal(jsonBytes, facebookSuccessJsonBytes) {
- return nil
- }
-
- jsonReader := bytes.NewReader(jsonBytes)
- dec := json.NewDecoder(jsonReader)
-
- // issue #19
- // app_scoped user_id in a post-Facebook graph 2.0 would exceeds 2^53.
- // use Number instead of float64 to avoid precision lost.
- dec.UseNumber()
-
- err := dec.Decode(res)
-
- if err != nil {
- typ := reflect.TypeOf(res)
-
- if typ != nil {
- // if res is a slice, jsonBytes may be a facebook error.
- // try to decode it as Error.
- kind := typ.Kind()
-
- if kind == reflect.Ptr {
- typ = typ.Elem()
- kind = typ.Kind()
- }
-
- if kind == reflect.Array || kind == reflect.Slice {
- var errRes Result
- err = makeResult(jsonBytes, &errRes)
-
- if err != nil {
- return err
- }
-
- err = errRes.Err()
-
- if err == nil {
- err = fmt.Errorf("cannot format facebook response. expect an array but get an object.")
- }
-
- return err
- }
- }
-
- return fmt.Errorf("cannot format facebook response. %v", err)
- }
-
- return nil
-}
-
-// Get gets a field from Result.
-//
-// Field can be a dot separated string.
-// If field name is "a.b.c", it will try to return value of res["a"]["b"]["c"].
-//
-// To access array items, use index value in field.
-// For instance, field "a.0.c" means to read res["a"][0]["c"].
-//
-// It doesn't work with Result which has a key contains dot. Use GetField in this case.
-//
-// Returns nil if field doesn't exist.
-func (res Result) Get(field string) interface{} {
- if field == "" {
- return res
- }
-
- f := strings.Split(field, ".")
- return res.get(f)
-}
-
-// GetField gets a field from Result.
-//
-// Arguments are treated as keys to access value in Result.
-// If arguments are "a","b","c", it will try to return value of res["a"]["b"]["c"].
-//
-// To access array items, use index value as a string.
-// For instance, args of "a", "0", "c" means to read res["a"][0]["c"].
-//
-// Returns nil if field doesn't exist.
-func (res Result) GetField(fields ...string) interface{} {
- if len(fields) == 0 {
- return res
- }
-
- return res.get(fields)
-}
-
-func (res Result) get(fields []string) interface{} {
- v, ok := res[fields[0]]
-
- if !ok || v == nil {
- return nil
- }
-
- if len(fields) == 1 {
- return v
- }
-
- value := getValueField(reflect.ValueOf(v), fields[1:])
-
- if !value.IsValid() {
- return nil
- }
-
- return value.Interface()
-}
-
-func getValueField(value reflect.Value, fields []string) reflect.Value {
- valueType := value.Type()
- kind := valueType.Kind()
- field := fields[0]
-
- switch kind {
- case reflect.Array, reflect.Slice:
- // field must be a number.
- n, err := strconv.ParseUint(field, 10, 0)
-
- if err != nil {
- return reflect.Value{}
- }
-
- if n >= uint64(value.Len()) {
- return reflect.Value{}
- }
-
- // work around a reflect package pitfall.
- value = reflect.ValueOf(value.Index(int(n)).Interface())
-
- case reflect.Map:
- v := value.MapIndex(reflect.ValueOf(field))
-
- if !v.IsValid() {
- return v
- }
-
- // get real value type.
- value = reflect.ValueOf(v.Interface())
-
- default:
- return reflect.Value{}
- }
-
- if len(fields) == 1 {
- return value
- }
-
- return getValueField(value, fields[1:])
-}
-
-// Decode decodes full result to a struct.
-// It only decodes fields defined in the struct.
-//
-// As all facebook response fields are lower case strings,
-// Decode will convert all camel-case field names to lower case string.
-// e.g. field name "FooBar" will be converted to "foo_bar".
-// The side effect is that if a struct has 2 fields with only capital
-// differences, decoder will map these fields to a same result value.
-//
-// If a field is missing in the result, Decode keeps it unchanged by default.
-//
-// Decode can read struct field tag value to change default behavior.
-//
-// Examples:
-//
-// type Foo struct {
-// // "id" must exist in response. note the leading comma.
-// Id string `facebook:",required"`
-//
-// // use "name" as field name in response.
-// TheName string `facebook:"name"`
-// }
-//
-// To change default behavior, set a struct tag `facebook:",required"` to fields
-// should not be missing.
-//
-// Returns error if v is not a struct or any required v field name absents in res.
-func (res Result) Decode(v interface{}) (err error) {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(runtime.Error); ok {
- panic(r)
- }
-
- err = r.(error)
- }
- }()
-
- err = res.decode(reflect.ValueOf(v), "")
- return
-}
-
-// DecodeField decodes a field of result to any type, including struct.
-// Field name format is defined in Result.Get().
-//
-// More details about decoding struct see Result.Decode().
-func (res Result) DecodeField(field string, v interface{}) error {
- f := res.Get(field)
-
- if f == nil {
- return fmt.Errorf("field '%v' doesn't exist in result.", field)
- }
-
- return decodeField(reflect.ValueOf(f), reflect.ValueOf(v), field)
-}
-
-// Err returns an error if Result is a Graph API error.
-//
-// The returned error can be converted to Error by type assertion.
-// err := res.Err()
-// if err != nil {
-// if e, ok := err.(*Error); ok {
-// // read more details in e.Message, e.Code and e.Type
-// }
-// }
-//
-// For more information about Graph API Errors, see
-// https://developers.facebook.com/docs/reference/api/errors/
-func (res Result) Err() error {
- var err Error
- e := res.DecodeField("error", &err)
-
- // no "error" in result. result is not an error.
- if e != nil {
- return nil
- }
-
- // code may be missing in error.
- // assign a non-zero value to it.
- if err.Code == 0 {
- err.Code = ERROR_CODE_UNKNOWN
- }
-
- return &err
-}
-
-// Paging creates a PagingResult for this Result and
-// returns error if the Result cannot be used for paging.
-//
-// Facebook uses following JSON structure to response paging information.
-// If "data" doesn't present in Result, Paging will return error.
-// {
-// "data": [...],
-// "paging": {
-// "previous": "https://graph.facebook.com/...",
-// "next": "https://graph.facebook.com/..."
-// }
-// }
-func (res Result) Paging(session *Session) (*PagingResult, error) {
- return newPagingResult(session, res)
-}
-
-// Batch creates a BatchResult for this result and
-// returns error if the Result is not a batch api response.
-//
-// See BatchApi document for a sample usage.
-func (res Result) Batch() (*BatchResult, error) {
- return newBatchResult(res)
-}
-
-// DebugInfo creates a DebugInfo for this result if this result
-// has "__debug__" key.
-func (res Result) DebugInfo() *DebugInfo {
- var info Result
- err := res.DecodeField(debugInfoKey, &info)
-
- if err != nil {
- return nil
- }
-
- debugInfo := &DebugInfo{}
- info.DecodeField("messages", &debugInfo.Messages)
-
- if proto, ok := info[debugProtoKey]; ok {
- if v, ok := proto.(string); ok {
- debugInfo.Proto = v
- }
- }
-
- if header, ok := info[debugHeaderKey]; ok {
- if v, ok := header.(http.Header); ok {
- debugInfo.Header = v
-
- debugInfo.FacebookApiVersion = v.Get(facebookApiVersionHeader)
- debugInfo.FacebookDebug = v.Get(facebookDebugHeader)
- debugInfo.FacebookRev = v.Get(facebookRevHeader)
- }
- }
-
- return debugInfo
-}
-
-func (res Result) decode(v reflect.Value, fullName string) error {
- for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
- v = v.Elem()
- }
-
- if v.Kind() != reflect.Struct {
- return fmt.Errorf("output value must be a struct.")
- }
-
- if !v.CanSet() {
- return fmt.Errorf("output value cannot be set.")
- }
-
- if fullName != "" {
- fullName += "."
- }
-
- var field reflect.Value
- var name, fbTag string
- var val interface{}
- var ok, required bool
- var err error
-
- vType := v.Type()
- num := vType.NumField()
-
- for i := 0; i < num; i++ {
- name = ""
- required = false
- field = v.Field(i)
- fbTag = vType.Field(i).Tag.Get("facebook")
-
- // parse struct field tag
- if fbTag != "" {
- index := strings.IndexRune(fbTag, ',')
-
- if index == -1 {
- name = fbTag
- } else {
- name = fbTag[:index]
-
- if fbTag[index:] == ",required" {
- required = true
- }
- }
- }
-
- if name == "" {
- name = camelCaseToUnderScore(v.Type().Field(i).Name)
- }
-
- val, ok = res[name]
-
- if !ok {
- // check whether the field is required. if so, report error.
- if required {
- return fmt.Errorf("cannot find field '%v%v' in result.", fullName, name)
- }
-
- continue
- }
-
- if err = decodeField(reflect.ValueOf(val), field, fmt.Sprintf("%v%v", fullName, name)); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func decodeField(val reflect.Value, field reflect.Value, fullName string) error {
- if field.Kind() == reflect.Ptr {
- // reset Ptr field if val is nil.
- if !val.IsValid() {
- if !field.IsNil() && field.CanSet() {
- field.Set(reflect.Zero(field.Type()))
- }
-
- return nil
- }
-
- if field.IsNil() {
- field.Set(reflect.New(field.Type().Elem()))
- }
-
- field = field.Elem()
- }
-
- if !field.CanSet() {
- return fmt.Errorf("field '%v' cannot be decoded. make sure the output value is able to be set.", fullName)
- }
-
- if !val.IsValid() {
- return fmt.Errorf("field '%v' is not a pointer. cannot assign nil to it.", fullName)
- }
-
- kind := field.Kind()
- valType := val.Type()
-
- switch kind {
- case reflect.Bool:
- if valType.Kind() == reflect.Bool {
- field.SetBool(val.Bool())
- } else {
- return fmt.Errorf("field '%v' is not a bool in result.", fullName)
- }
-
- case reflect.Int8:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < -128 || n > 127 {
- return fmt.Errorf("field '%v' value exceeds the range of int8.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > 127 {
- return fmt.Errorf("field '%v' value exceeds the range of int8.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < -128 || n > 127 {
- return fmt.Errorf("field '%v' value exceeds the range of int8.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseInt(val.String(), 10, 8)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid int8.", fullName)
- }
-
- field.SetInt(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Int16:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < -32768 || n > 32767 {
- return fmt.Errorf("field '%v' value exceeds the range of int16.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > 32767 {
- return fmt.Errorf("field '%v' value exceeds the range of int16.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < -32768 || n > 32767 {
- return fmt.Errorf("field '%v' value exceeds the range of int16.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseInt(val.String(), 10, 16)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid int16.", fullName)
- }
-
- field.SetInt(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Int32:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < -2147483648 || n > 2147483647 {
- return fmt.Errorf("field '%v' value exceeds the range of int32.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > 2147483647 {
- return fmt.Errorf("field '%v' value exceeds the range of int32.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < -2147483648 || n > 2147483647 {
- return fmt.Errorf("field '%v' value exceeds the range of int32.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseInt(val.String(), 10, 32)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid int32.", fullName)
- }
-
- field.SetInt(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Int64:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
- field.SetInt(n)
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > 9223372036854775807 {
- return fmt.Errorf("field '%v' value exceeds the range of int64.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < -9223372036854775808 || n > 9223372036854775807 {
- return fmt.Errorf("field '%v' value exceeds the range of int64.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseInt(val.String(), 10, 64)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid int64.", fullName)
- }
-
- field.SetInt(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Int:
- bits := field.Type().Bits()
-
- var min, max int64
-
- if bits == 32 {
- min = -2147483648
- max = 2147483647
- } else if bits == 64 {
- min = -9223372036854775808
- max = 9223372036854775807
- }
-
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < min || n > max {
- return fmt.Errorf("field '%v' value exceeds the range of int.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > uint64(max) {
- return fmt.Errorf("field '%v' value exceeds the range of int.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < float64(min) || n > float64(max) {
- return fmt.Errorf("field '%v' value exceeds the range of int.", fullName)
- }
-
- field.SetInt(int64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseInt(val.String(), 10, bits)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid int%v.", fullName, bits)
- }
-
- field.SetInt(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Uint8:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < 0 || n > 0xFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint8.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > 0xFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint8.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < 0 || n > 0xFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint8.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseUint(val.String(), 10, 8)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid uint8.", fullName)
- }
-
- field.SetUint(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Uint16:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < 0 || n > 0xFFFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint16.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > 0xFFFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint16.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < 0 || n > 0xFFFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint16.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseUint(val.String(), 10, 16)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid uint16.", fullName)
- }
-
- field.SetUint(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Uint32:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < 0 || n > 0xFFFFFFFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint32.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > 0xFFFFFFFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint32.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < 0 || n > 0xFFFFFFFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint32.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseUint(val.String(), 10, 32)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid uint32.", fullName)
- }
-
- field.SetUint(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Uint64:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < 0 {
- return fmt.Errorf("field '%v' value exceeds the range of uint64.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
- field.SetUint(n)
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < 0 || n > 0xFFFFFFFFFFFFFFFF {
- return fmt.Errorf("field '%v' value exceeds the range of uint64.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseUint(val.String(), 10, 64)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid uint64.", fullName)
- }
-
- field.SetUint(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Uint:
- bits := field.Type().Bits()
-
- var max uint64
-
- if bits == 32 {
- max = 0xFFFFFFFF
- } else if bits == 64 {
- max = 0xFFFFFFFFFFFFFFFF
- }
-
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
-
- if n < 0 || uint64(n) > max {
- return fmt.Errorf("field '%v' value exceeds the range of uint.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
-
- if n > max {
- return fmt.Errorf("field '%v' value exceeds the range of uint.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
-
- if n < 0 || n > float64(max) {
- return fmt.Errorf("field '%v' value exceeds the range of uint.", fullName)
- }
-
- field.SetUint(uint64(n))
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseUint(val.String(), 10, bits)
-
- if err != nil {
- return fmt.Errorf("field '%v' value is not a valid uint%v.", fullName, bits)
- }
-
- field.SetUint(n)
-
- default:
- return fmt.Errorf("field '%v' is not an integer in result.", fullName)
- }
-
- case reflect.Float32, reflect.Float64:
- switch valType.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n := val.Int()
- field.SetFloat(float64(n))
-
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- n := val.Uint()
- field.SetFloat(float64(n))
-
- case reflect.Float32, reflect.Float64:
- n := val.Float()
- field.SetFloat(n)
-
- case reflect.String:
- // only json.Number is allowed to be used as number.
- if val.Type() != typeOfJSONNumber {
- return fmt.Errorf("field '%v' value is string, not a number.", fullName)
- }
-
- n, err := strconv.ParseFloat(val.String(), 64)
-
- if err != nil {
- return fmt.Errorf("field '%v' is not a valid float64.", fullName)
- }
-
- field.SetFloat(n)
-
- default:
- return fmt.Errorf("field '%v' is not a float in result.", fullName)
- }
-
- case reflect.String:
- if valType.Kind() != reflect.String {
- return fmt.Errorf("field '%v' is not a string in result.", fullName)
- }
-
- field.SetString(val.String())
-
- case reflect.Struct:
- if field.Type().ConvertibleTo(typeOfTime) {
- if valType.Kind() != reflect.String {
- return fmt.Errorf("field '%v' is not a string in result.", fullName)
- }
-
- t, err := time.Parse("2006-01-02T15:04:05-0700", val.String())
-
- if err != nil {
- return fmt.Errorf("field '%v' was unable to parse the time string '%s'.", fullName, val.String())
- }
-
- matchedType := reflect.ValueOf(t).Convert(field.Type())
- field.Set(matchedType)
- return nil
- }
-
- if valType.Kind() != reflect.Map || valType.Key().Kind() != reflect.String {
- return fmt.Errorf("field '%v' is not a json object in result.", fullName)
- }
-
- // safe convert val to Result. type assertion doesn't work in this case.
- var r Result
- reflect.ValueOf(&r).Elem().Set(val)
-
- if err := r.decode(field, fullName); err != nil {
- return err
- }
-
- case reflect.Map:
- if valType.Kind() != reflect.Map || valType.Key().Kind() != reflect.String {
- return fmt.Errorf("field '%v' is not a json object in result.", fullName)
- }
-
- // map key must be string
- if field.Type().Key().Kind() != reflect.String {
- return fmt.Errorf("field '%v' in struct is a map with non-string key type. it's not allowed.", fullName)
- }
-
- var needAddr bool
- valueType := field.Type().Elem()
-
- // shortcut for map[string]interface{}.
- if valueType.Kind() == reflect.Interface {
- field.Set(val)
- break
- }
-
- if field.IsNil() {
- field.Set(reflect.MakeMap(field.Type()))
- }
-
- if valueType.Kind() == reflect.Ptr {
- valueType = valueType.Elem()
- needAddr = true
- }
-
- for _, key := range val.MapKeys() {
- // val.MapIndex(key) returns a Value with wrong type.
- // use following trick to get correct Value.
- value := reflect.ValueOf(val.MapIndex(key).Interface())
- newValue := reflect.New(valueType)
-
- if err := decodeField(value, newValue, fmt.Sprintf("%v.%v", fullName, key)); err != nil {
- return err
- }
-
- if needAddr {
- field.SetMapIndex(key, newValue)
- } else {
- field.SetMapIndex(key, newValue.Elem())
- }
- }
-
- case reflect.Slice, reflect.Array:
- if valType.Kind() != reflect.Slice && valType.Kind() != reflect.Array {
- return fmt.Errorf("field '%v' is not a json array in result.", fullName)
- }
-
- valLen := val.Len()
-
- if kind == reflect.Array {
- if field.Len() < valLen {
- return fmt.Errorf("cannot copy all field '%v' values to struct. expected len is %v. actual len is %v.",
- fullName, field.Len(), valLen)
- }
- }
-
- var slc reflect.Value
- var needAddr bool
-
- valueType := field.Type().Elem()
-
- // shortcut for array of interface
- if valueType.Kind() == reflect.Interface {
- if kind == reflect.Array {
- for i := 0; i < valLen; i++ {
- field.Index(i).Set(val.Index(i))
- }
- } else { // kind is slice
- field.Set(val)
- }
-
- break
- }
-
- if kind == reflect.Array {
- slc = field.Slice(0, valLen)
- } else {
- // kind is slice
- slc = reflect.MakeSlice(field.Type(), valLen, valLen)
- field.Set(slc)
- }
-
- if valueType.Kind() == reflect.Ptr {
- needAddr = true
- valueType = valueType.Elem()
- }
-
- for i := 0; i < valLen; i++ {
- // val.Index(i) returns a Value with wrong type.
- // use following trick to get correct Value.
- valIndexValue := reflect.ValueOf(val.Index(i).Interface())
- newValue := reflect.New(valueType)
-
- if err := decodeField(valIndexValue, newValue, fmt.Sprintf("%v.%v", fullName, i)); err != nil {
- return err
- }
-
- if needAddr {
- slc.Index(i).Set(newValue)
- } else {
- slc.Index(i).Set(newValue.Elem())
- }
- }
-
- default:
- return fmt.Errorf("field '%v' in struct uses unsupported type '%v'.", fullName, kind)
- }
-
- return nil
-}