OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / btcjson / cmdparse.go
diff --git a/vendor/github.com/btcsuite/btcd/btcjson/cmdparse.go b/vendor/github.com/btcsuite/btcd/btcjson/cmdparse.go
deleted file mode 100644 (file)
index abe52e3..0000000
+++ /dev/null
@@ -1,550 +0,0 @@
-// Copyright (c) 2014 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package btcjson
-
-import (
-       "encoding/json"
-       "fmt"
-       "reflect"
-       "strconv"
-       "strings"
-)
-
-// makeParams creates a slice of interface values for the given struct.
-func makeParams(rt reflect.Type, rv reflect.Value) []interface{} {
-       numFields := rt.NumField()
-       params := make([]interface{}, 0, numFields)
-       for i := 0; i < numFields; i++ {
-               rtf := rt.Field(i)
-               rvf := rv.Field(i)
-               if rtf.Type.Kind() == reflect.Ptr {
-                       if rvf.IsNil() {
-                               break
-                       }
-                       rvf.Elem()
-               }
-               params = append(params, rvf.Interface())
-       }
-
-       return params
-}
-
-// MarshalCmd marshals the passed command to a JSON-RPC request byte slice that
-// is suitable for transmission to an RPC server.  The provided command type
-// must be a registered type.  All commands provided by this package are
-// registered by default.
-func MarshalCmd(id interface{}, cmd interface{}) ([]byte, error) {
-       // Look up the cmd type and error out if not registered.
-       rt := reflect.TypeOf(cmd)
-       registerLock.RLock()
-       method, ok := concreteTypeToMethod[rt]
-       registerLock.RUnlock()
-       if !ok {
-               str := fmt.Sprintf("%q is not registered", method)
-               return nil, makeError(ErrUnregisteredMethod, str)
-       }
-
-       // The provided command must not be nil.
-       rv := reflect.ValueOf(cmd)
-       if rv.IsNil() {
-               str := "the specified command is nil"
-               return nil, makeError(ErrInvalidType, str)
-       }
-
-       // Create a slice of interface values in the order of the struct fields
-       // while respecting pointer fields as optional params and only adding
-       // them if they are non-nil.
-       params := makeParams(rt.Elem(), rv.Elem())
-
-       // Generate and marshal the final JSON-RPC request.
-       rawCmd, err := NewRequest(id, method, params)
-       if err != nil {
-               return nil, err
-       }
-       return json.Marshal(rawCmd)
-}
-
-// checkNumParams ensures the supplied number of params is at least the minimum
-// required number for the command and less than the maximum allowed.
-func checkNumParams(numParams int, info *methodInfo) error {
-       if numParams < info.numReqParams || numParams > info.maxParams {
-               if info.numReqParams == info.maxParams {
-                       str := fmt.Sprintf("wrong number of params (expected "+
-                               "%d, received %d)", info.numReqParams,
-                               numParams)
-                       return makeError(ErrNumParams, str)
-               }
-
-               str := fmt.Sprintf("wrong number of params (expected "+
-                       "between %d and %d, received %d)", info.numReqParams,
-                       info.maxParams, numParams)
-               return makeError(ErrNumParams, str)
-       }
-
-       return nil
-}
-
-// populateDefaults populates default values into any remaining optional struct
-// fields that did not have parameters explicitly provided.  The caller should
-// have previously checked that the number of parameters being passed is at
-// least the required number of parameters to avoid unnecessary work in this
-// function, but since required fields never have default values, it will work
-// properly even without the check.
-func populateDefaults(numParams int, info *methodInfo, rv reflect.Value) {
-       // When there are no more parameters left in the supplied parameters,
-       // any remaining struct fields must be optional.  Thus, populate them
-       // with their associated default value as needed.
-       for i := numParams; i < info.maxParams; i++ {
-               rvf := rv.Field(i)
-               if defaultVal, ok := info.defaults[i]; ok {
-                       rvf.Set(defaultVal)
-               }
-       }
-}
-
-// UnmarshalCmd unmarshals a JSON-RPC request into a suitable concrete command
-// so long as the method type contained within the marshalled request is
-// registered.
-func UnmarshalCmd(r *Request) (interface{}, error) {
-       registerLock.RLock()
-       rtp, ok := methodToConcreteType[r.Method]
-       info := methodToInfo[r.Method]
-       registerLock.RUnlock()
-       if !ok {
-               str := fmt.Sprintf("%q is not registered", r.Method)
-               return nil, makeError(ErrUnregisteredMethod, str)
-       }
-       rt := rtp.Elem()
-       rvp := reflect.New(rt)
-       rv := rvp.Elem()
-
-       // Ensure the number of parameters are correct.
-       numParams := len(r.Params)
-       if err := checkNumParams(numParams, &info); err != nil {
-               return nil, err
-       }
-
-       // Loop through each of the struct fields and unmarshal the associated
-       // parameter into them.
-       for i := 0; i < numParams; i++ {
-               rvf := rv.Field(i)
-               // Unmarshal the parameter into the struct field.
-               concreteVal := rvf.Addr().Interface()
-               if err := json.Unmarshal(r.Params[i], &concreteVal); err != nil {
-                       // The most common error is the wrong type, so
-                       // explicitly detect that error and make it nicer.
-                       fieldName := strings.ToLower(rt.Field(i).Name)
-                       if jerr, ok := err.(*json.UnmarshalTypeError); ok {
-                               str := fmt.Sprintf("parameter #%d '%s' must "+
-                                       "be type %v (got %v)", i+1, fieldName,
-                                       jerr.Type, jerr.Value)
-                               return nil, makeError(ErrInvalidType, str)
-                       }
-
-                       // Fallback to showing the underlying error.
-                       str := fmt.Sprintf("parameter #%d '%s' failed to "+
-                               "unmarshal: %v", i+1, fieldName, err)
-                       return nil, makeError(ErrInvalidType, str)
-               }
-       }
-
-       // When there are less supplied parameters than the total number of
-       // params, any remaining struct fields must be optional.  Thus, populate
-       // them with their associated default value as needed.
-       if numParams < info.maxParams {
-               populateDefaults(numParams, &info, rv)
-       }
-
-       return rvp.Interface(), nil
-}
-
-// isNumeric returns whether the passed reflect kind is a signed or unsigned
-// integer of any magnitude or a float of any magnitude.
-func isNumeric(kind reflect.Kind) bool {
-       switch kind {
-       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
-               reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
-               reflect.Uint64, reflect.Float32, reflect.Float64:
-
-               return true
-       }
-
-       return false
-}
-
-// typesMaybeCompatible returns whether the source type can possibly be
-// assigned to the destination type.  This is intended as a relatively quick
-// check to weed out obviously invalid conversions.
-func typesMaybeCompatible(dest reflect.Type, src reflect.Type) bool {
-       // The same types are obviously compatible.
-       if dest == src {
-               return true
-       }
-
-       // When both types are numeric, they are potentially compatibile.
-       srcKind := src.Kind()
-       destKind := dest.Kind()
-       if isNumeric(destKind) && isNumeric(srcKind) {
-               return true
-       }
-
-       if srcKind == reflect.String {
-               // Strings can potentially be converted to numeric types.
-               if isNumeric(destKind) {
-                       return true
-               }
-
-               switch destKind {
-               // Strings can potentially be converted to bools by
-               // strconv.ParseBool.
-               case reflect.Bool:
-                       return true
-
-               // Strings can be converted to any other type which has as
-               // underlying type of string.
-               case reflect.String:
-                       return true
-
-               // Strings can potentially be converted to arrays, slice,
-               // structs, and maps via json.Unmarshal.
-               case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map:
-                       return true
-               }
-       }
-
-       return false
-}
-
-// baseType returns the type of the argument after indirecting through all
-// pointers along with how many indirections were necessary.
-func baseType(arg reflect.Type) (reflect.Type, int) {
-       var numIndirects int
-       for arg.Kind() == reflect.Ptr {
-               arg = arg.Elem()
-               numIndirects++
-       }
-       return arg, numIndirects
-}
-
-// assignField is the main workhorse for the NewCmd function which handles
-// assigning the provided source value to the destination field.  It supports
-// direct type assignments, indirection, conversion of numeric types, and
-// unmarshaling of strings into arrays, slices, structs, and maps via
-// json.Unmarshal.
-func assignField(paramNum int, fieldName string, dest reflect.Value, src reflect.Value) error {
-       // Just error now when the types have no chance of being compatible.
-       destBaseType, destIndirects := baseType(dest.Type())
-       srcBaseType, srcIndirects := baseType(src.Type())
-       if !typesMaybeCompatible(destBaseType, srcBaseType) {
-               str := fmt.Sprintf("parameter #%d '%s' must be type %v (got "+
-                       "%v)", paramNum, fieldName, destBaseType, srcBaseType)
-               return makeError(ErrInvalidType, str)
-       }
-
-       // Check if it's possible to simply set the dest to the provided source.
-       // This is the case when the base types are the same or they are both
-       // pointers that can be indirected to be the same without needing to
-       // create pointers for the destination field.
-       if destBaseType == srcBaseType && srcIndirects >= destIndirects {
-               for i := 0; i < srcIndirects-destIndirects; i++ {
-                       src = src.Elem()
-               }
-               dest.Set(src)
-               return nil
-       }
-
-       // When the destination has more indirects than the source, the extra
-       // pointers have to be created.  Only create enough pointers to reach
-       // the same level of indirection as the source so the dest can simply be
-       // set to the provided source when the types are the same.
-       destIndirectsRemaining := destIndirects
-       if destIndirects > srcIndirects {
-               indirectDiff := destIndirects - srcIndirects
-               for i := 0; i < indirectDiff; i++ {
-                       dest.Set(reflect.New(dest.Type().Elem()))
-                       dest = dest.Elem()
-                       destIndirectsRemaining--
-               }
-       }
-
-       if destBaseType == srcBaseType {
-               dest.Set(src)
-               return nil
-       }
-
-       // Make any remaining pointers needed to get to the base dest type since
-       // the above direct assign was not possible and conversions are done
-       // against the base types.
-       for i := 0; i < destIndirectsRemaining; i++ {
-               dest.Set(reflect.New(dest.Type().Elem()))
-               dest = dest.Elem()
-       }
-
-       // Indirect through to the base source value.
-       for src.Kind() == reflect.Ptr {
-               src = src.Elem()
-       }
-
-       // Perform supported type conversions.
-       switch src.Kind() {
-       // Source value is a signed integer of various magnitude.
-       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
-               reflect.Int64:
-
-               switch dest.Kind() {
-               // Destination is a signed integer of various magnitude.
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
-                       reflect.Int64:
-
-                       srcInt := src.Int()
-                       if dest.OverflowInt(srcInt) {
-                               str := fmt.Sprintf("parameter #%d '%s' "+
-                                       "overflows destination type %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-
-                       dest.SetInt(srcInt)
-
-               // Destination is an unsigned integer of various magnitude.
-               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
-                       reflect.Uint64:
-
-                       srcInt := src.Int()
-                       if srcInt < 0 || dest.OverflowUint(uint64(srcInt)) {
-                               str := fmt.Sprintf("parameter #%d '%s' "+
-                                       "overflows destination type %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       dest.SetUint(uint64(srcInt))
-
-               default:
-                       str := fmt.Sprintf("parameter #%d '%s' must be type "+
-                               "%v (got %v)", paramNum, fieldName, destBaseType,
-                               srcBaseType)
-                       return makeError(ErrInvalidType, str)
-               }
-
-       // Source value is an unsigned integer of various magnitude.
-       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
-               reflect.Uint64:
-
-               switch dest.Kind() {
-               // Destination is a signed integer of various magnitude.
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
-                       reflect.Int64:
-
-                       srcUint := src.Uint()
-                       if srcUint > uint64(1<<63)-1 {
-                               str := fmt.Sprintf("parameter #%d '%s' "+
-                                       "overflows destination type %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       if dest.OverflowInt(int64(srcUint)) {
-                               str := fmt.Sprintf("parameter #%d '%s' "+
-                                       "overflows destination type %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       dest.SetInt(int64(srcUint))
-
-               // Destination is an unsigned integer of various magnitude.
-               case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
-                       reflect.Uint64:
-
-                       srcUint := src.Uint()
-                       if dest.OverflowUint(srcUint) {
-                               str := fmt.Sprintf("parameter #%d '%s' "+
-                                       "overflows destination type %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       dest.SetUint(srcUint)
-
-               default:
-                       str := fmt.Sprintf("parameter #%d '%s' must be type "+
-                               "%v (got %v)", paramNum, fieldName, destBaseType,
-                               srcBaseType)
-                       return makeError(ErrInvalidType, str)
-               }
-
-       // Source value is a float.
-       case reflect.Float32, reflect.Float64:
-               destKind := dest.Kind()
-               if destKind != reflect.Float32 && destKind != reflect.Float64 {
-                       str := fmt.Sprintf("parameter #%d '%s' must be type "+
-                               "%v (got %v)", paramNum, fieldName, destBaseType,
-                               srcBaseType)
-                       return makeError(ErrInvalidType, str)
-               }
-
-               srcFloat := src.Float()
-               if dest.OverflowFloat(srcFloat) {
-                       str := fmt.Sprintf("parameter #%d '%s' overflows "+
-                               "destination type %v", paramNum, fieldName,
-                               destBaseType)
-                       return makeError(ErrInvalidType, str)
-               }
-               dest.SetFloat(srcFloat)
-
-       // Source value is a string.
-       case reflect.String:
-               switch dest.Kind() {
-               // String -> bool
-               case reflect.Bool:
-                       b, err := strconv.ParseBool(src.String())
-                       if err != nil {
-                               str := fmt.Sprintf("parameter #%d '%s' must "+
-                                       "parse to a %v", paramNum, fieldName,
-                                       destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       dest.SetBool(b)
-
-               // String -> signed integer of varying size.
-               case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
-                       reflect.Int64:
-
-                       srcInt, err := strconv.ParseInt(src.String(), 0, 0)
-                       if err != nil {
-                               str := fmt.Sprintf("parameter #%d '%s' must "+
-                                       "parse to a %v", paramNum, fieldName,
-                                       destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       if dest.OverflowInt(srcInt) {
-                               str := fmt.Sprintf("parameter #%d '%s' "+
-                                       "overflows destination type %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       dest.SetInt(srcInt)
-
-               // String -> unsigned integer of varying size.
-               case reflect.Uint, reflect.Uint8, reflect.Uint16,
-                       reflect.Uint32, reflect.Uint64:
-
-                       srcUint, err := strconv.ParseUint(src.String(), 0, 0)
-                       if err != nil {
-                               str := fmt.Sprintf("parameter #%d '%s' must "+
-                                       "parse to a %v", paramNum, fieldName,
-                                       destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       if dest.OverflowUint(srcUint) {
-                               str := fmt.Sprintf("parameter #%d '%s' "+
-                                       "overflows destination type %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       dest.SetUint(srcUint)
-
-               // String -> float of varying size.
-               case reflect.Float32, reflect.Float64:
-                       srcFloat, err := strconv.ParseFloat(src.String(), 0)
-                       if err != nil {
-                               str := fmt.Sprintf("parameter #%d '%s' must "+
-                                       "parse to a %v", paramNum, fieldName,
-                                       destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       if dest.OverflowFloat(srcFloat) {
-                               str := fmt.Sprintf("parameter #%d '%s' "+
-                                       "overflows destination type %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       dest.SetFloat(srcFloat)
-
-               // String -> string (typecast).
-               case reflect.String:
-                       dest.SetString(src.String())
-
-               // String -> arrays, slices, structs, and maps via
-               // json.Unmarshal.
-               case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map:
-                       concreteVal := dest.Addr().Interface()
-                       err := json.Unmarshal([]byte(src.String()), &concreteVal)
-                       if err != nil {
-                               str := fmt.Sprintf("parameter #%d '%s' must "+
-                                       "be valid JSON which unsmarshals to a %v",
-                                       paramNum, fieldName, destBaseType)
-                               return makeError(ErrInvalidType, str)
-                       }
-                       dest.Set(reflect.ValueOf(concreteVal).Elem())
-               }
-       }
-
-       return nil
-}
-
-// NewCmd provides a generic mechanism to create a new command that can marshal
-// to a JSON-RPC request while respecting the requirements of the provided
-// method.  The method must have been registered with the package already along
-// with its type definition.  All methods associated with the commands exported
-// by this package are already registered by default.
-//
-// The arguments are most efficient when they are the exact same type as the
-// underlying field in the command struct associated with the the method,
-// however this function also will perform a variety of conversions to make it
-// more flexible.  This allows, for example, command line args which are strings
-// to be passed unaltered.  In particular, the following conversions are
-// supported:
-//
-//   - Conversion between any size signed or unsigned integer so long as the
-//     value does not overflow the destination type
-//   - Conversion between float32 and float64 so long as the value does not
-//     overflow the destination type
-//   - Conversion from string to boolean for everything strconv.ParseBool
-//     recognizes
-//   - Conversion from string to any size integer for everything
-//     strconv.ParseInt and strconv.ParseUint recognizes
-//   - Conversion from string to any size float for everything
-//     strconv.ParseFloat recognizes
-//   - Conversion from string to arrays, slices, structs, and maps by treating
-//     the string as marshalled JSON and calling json.Unmarshal into the
-//     destination field
-func NewCmd(method string, args ...interface{}) (interface{}, error) {
-       // Look up details about the provided method.  Any methods that aren't
-       // registered are an error.
-       registerLock.RLock()
-       rtp, ok := methodToConcreteType[method]
-       info := methodToInfo[method]
-       registerLock.RUnlock()
-       if !ok {
-               str := fmt.Sprintf("%q is not registered", method)
-               return nil, makeError(ErrUnregisteredMethod, str)
-       }
-
-       // Ensure the number of parameters are correct.
-       numParams := len(args)
-       if err := checkNumParams(numParams, &info); err != nil {
-               return nil, err
-       }
-
-       // Create the appropriate command type for the method.  Since all types
-       // are enforced to be a pointer to a struct at registration time, it's
-       // safe to indirect to the struct now.
-       rvp := reflect.New(rtp.Elem())
-       rv := rvp.Elem()
-       rt := rtp.Elem()
-
-       // Loop through each of the struct fields and assign the associated
-       // parameter into them after checking its type validity.
-       for i := 0; i < numParams; i++ {
-               // Attempt to assign each of the arguments to the according
-               // struct field.
-               rvf := rv.Field(i)
-               fieldName := strings.ToLower(rt.Field(i).Name)
-               err := assignField(i+1, fieldName, rvf, reflect.ValueOf(args[i]))
-               if err != nil {
-                       return nil, err
-               }
-       }
-
-       return rvp.Interface(), nil
-}