github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/accounts/abi/type.go (about)

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