github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/accounts/abi/type.go (about)

     1  package abi
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"regexp"
     7  	"strconv"
     8  	"strings"
     9  )
    10  
    11  // Type enumerator
    12  const (
    13  	IntTy byte = iota
    14  	UintTy
    15  	BoolTy
    16  	StringTy
    17  	SliceTy
    18  	ArrayTy
    19  	AddressTy
    20  	FixedBytesTy
    21  	BytesTy
    22  	HashTy
    23  	FixedPointTy
    24  	FunctionTy
    25  )
    26  
    27  // Type is the reflection of the supported argument type
    28  type Type struct {
    29  	Elem *Type
    30  
    31  	Kind reflect.Kind
    32  	Type reflect.Type
    33  	Size int
    34  	T    byte // Our own type checking
    35  
    36  	stringKind string // holds the unparsed string for deriving signatures
    37  }
    38  
    39  var (
    40  	// typeRegex parses the abi sub types
    41  	typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
    42  )
    43  
    44  // NewType creates a new reflection type of abi type given in t.
    45  func NewType(t string) (typ Type, err error) {
    46  	// check that array brackets are equal if they exist
    47  	if strings.Count(t, "[") != strings.Count(t, "]") {
    48  		return Type{}, fmt.Errorf("invalid arg type in abi")
    49  	}
    50  
    51  	typ.stringKind = t
    52  
    53  	// if there are brackets, get ready to go into slice/array mode and
    54  	// recursively create the type
    55  	if strings.Count(t, "[") != 0 {
    56  		i := strings.LastIndex(t, "[")
    57  		// recursively embed the type
    58  		embeddedType, err := NewType(t[:i])
    59  		if err != nil {
    60  			return Type{}, err
    61  		}
    62  		// grab the last cell and create a type from there
    63  		sliced := t[i:]
    64  		// grab the slice size with regexp
    65  		re := regexp.MustCompile("[0-9]+")
    66  		intz := re.FindAllString(sliced, -1)
    67  
    68  		if len(intz) == 0 {
    69  			// is a slice
    70  			typ.T = SliceTy
    71  			typ.Kind = reflect.Slice
    72  			typ.Elem = &embeddedType
    73  			typ.Type = reflect.SliceOf(embeddedType.Type)
    74  		} else if len(intz) == 1 {
    75  			// is a array
    76  			typ.T = ArrayTy
    77  			typ.Kind = reflect.Array
    78  			typ.Elem = &embeddedType
    79  			typ.Size, err = strconv.Atoi(intz[0])
    80  			if err != nil {
    81  				return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
    82  			}
    83  			typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
    84  		} else {
    85  			return Type{}, fmt.Errorf("invalid formatting of array type")
    86  		}
    87  		return typ, err
    88  	}
    89  	// parse the type and size of the abi-type.
    90  	parsedType := typeRegex.FindAllStringSubmatch(t, -1)[0]
    91  	// varSize is the size of the variable
    92  	var varSize int
    93  	if len(parsedType[3]) > 0 {
    94  		var err error
    95  		varSize, err = strconv.Atoi(parsedType[2])
    96  		if err != nil {
    97  			return Type{}, fmt.Errorf("abi: error parsing variable size: %v", err)
    98  		}
    99  	} else {
   100  		if parsedType[0] == "uint" || parsedType[0] == "int" {
   101  			// this should fail because it means that there's something wrong with
   102  			// the abi type (the compiler should always format it to the size...always)
   103  			return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   104  		}
   105  	}
   106  	// varType is the parsed abi type
   107  	switch varType := parsedType[1]; varType {
   108  	case "int":
   109  		typ.Kind, typ.Type = reflectIntKindAndType(false, varSize)
   110  		typ.Size = varSize
   111  		typ.T = IntTy
   112  	case "uint":
   113  		typ.Kind, typ.Type = reflectIntKindAndType(true, varSize)
   114  		typ.Size = varSize
   115  		typ.T = UintTy
   116  	case "bool":
   117  		typ.Kind = reflect.Bool
   118  		typ.T = BoolTy
   119  		typ.Type = reflect.TypeOf(bool(false))
   120  	case "address":
   121  		typ.Kind = reflect.Array
   122  		typ.Type = addressT
   123  		typ.Size = 20
   124  		typ.T = AddressTy
   125  	case "string":
   126  		typ.Kind = reflect.String
   127  		typ.Type = reflect.TypeOf("")
   128  		typ.T = StringTy
   129  	case "bytes":
   130  		if varSize == 0 {
   131  			typ.T = BytesTy
   132  			typ.Kind = reflect.Slice
   133  			typ.Type = reflect.SliceOf(reflect.TypeOf(byte(0)))
   134  		} else {
   135  			typ.T = FixedBytesTy
   136  			typ.Kind = reflect.Array
   137  			typ.Size = varSize
   138  			typ.Type = reflect.ArrayOf(varSize, reflect.TypeOf(byte(0)))
   139  		}
   140  	case "function":
   141  		typ.Kind = reflect.Array
   142  		typ.T = FunctionTy
   143  		typ.Size = 24
   144  		typ.Type = reflect.ArrayOf(24, reflect.TypeOf(byte(0)))
   145  	default:
   146  		return Type{}, fmt.Errorf("unsupported arg type: %s", t)
   147  	}
   148  
   149  	return
   150  }
   151  
   152  // String implements Stringer
   153  func (t Type) String() (out string) {
   154  	return t.stringKind
   155  }
   156  
   157  func (t Type) pack(v reflect.Value) ([]byte, error) {
   158  	// dereference pointer first if it's a pointer
   159  	v = indirect(v)
   160  
   161  	if err := typeCheck(t, v); err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	if t.T == SliceTy || t.T == ArrayTy {
   166  		var packed []byte
   167  
   168  		for i := 0; i < v.Len(); i++ {
   169  			val, err := t.Elem.pack(v.Index(i))
   170  			if err != nil {
   171  				return nil, err
   172  			}
   173  			packed = append(packed, val...)
   174  		}
   175  		if t.T == SliceTy {
   176  			return packBytesSlice(packed, v.Len()), nil
   177  		} else if t.T == ArrayTy {
   178  			return packed, nil
   179  		}
   180  	}
   181  	return packElement(t, v), nil
   182  }
   183  
   184  // requireLengthPrefix returns whether the type requires any sort of length
   185  // prefixing.
   186  func (t Type) requiresLengthPrefix() bool {
   187  	return t.T == StringTy || t.T == BytesTy || t.T == SliceTy
   188  }