github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/reflector/reflector.go (about)

     1  package reflector
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  	"sync"
     8  )
     9  
    10  type fieldListingType int
    11  
    12  const (
    13  	fieldsAll fieldListingType = iota
    14  	fieldsAnonymous
    15  	fieldsFlattenAnonymous
    16  	fieldsNoFlattenAnonymous
    17  )
    18  
    19  var (
    20  	metadataCache      = map[reflect.Type]*ObjMetadata{}
    21  	metadataCacheMutex sync.RWMutex
    22  )
    23  
    24  func updateCache(ty reflect.Type, o *Obj) {
    25  	metadataCacheMutex.Lock()
    26  	defer metadataCacheMutex.Unlock()
    27  
    28  	metadataCache[ty] = o.ObjMetadata
    29  }
    30  
    31  // ObjMetadata contains data which is always unique per Type.
    32  type ObjMetadata struct {
    33  	isStruct      bool
    34  	isPtrToStruct bool
    35  
    36  	// If ptr to struct, this field will contain the type of that struct
    37  	underlyingType reflect.Type
    38  
    39  	objType reflect.Type
    40  	objKind reflect.Kind
    41  
    42  	fields map[string]*ObjFieldMetadata
    43  
    44  	fieldNamesAll                []string
    45  	fieldNamesAnonymous          []string
    46  	fieldNamesFlattenAnonymous   []string
    47  	fieldNamesNoFlattenAnonymous []string
    48  
    49  	methods     map[string]*ObjMethodMetadata
    50  	methodNames []string
    51  }
    52  
    53  func newObjMetadata(ty reflect.Type) *ObjMetadata {
    54  	res := new(ObjMetadata)
    55  	if ty == nil {
    56  		res.objKind = reflect.Invalid
    57  		return res
    58  	}
    59  
    60  	res.objType = ty
    61  	res.objKind = res.objType.Kind()
    62  
    63  	if ty.Kind() == reflect.Struct {
    64  		res.isStruct = true
    65  	} else if ty.Kind() == reflect.Ptr && ty.Elem().Kind() == reflect.Struct {
    66  		ty = ty.Elem()
    67  		res.isPtrToStruct = true
    68  	}
    69  	res.underlyingType = ty
    70  
    71  	allFields := res.getFields(res.objType, fieldsAll)
    72  
    73  	res.fieldNamesAll = allFields
    74  	res.fieldNamesAnonymous = res.getFields(res.objType, fieldsAnonymous)
    75  	res.fieldNamesFlattenAnonymous = res.getFields(res.objType, fieldsFlattenAnonymous)
    76  	res.fieldNamesNoFlattenAnonymous = res.getFields(res.objType, fieldsNoFlattenAnonymous)
    77  
    78  	res.methods = map[string]*ObjMethodMetadata{}
    79  	res.methodNames = []string{}
    80  
    81  	if res.objKind != reflect.Invalid {
    82  		res.fields = map[string]*ObjFieldMetadata{}
    83  		for _, fieldName := range allFields {
    84  			metadata := newObjFieldMetadata(fieldName, res)
    85  			res.fields[fieldName] = metadata
    86  			res.fields[strings.ToLower(fieldName)] = metadata
    87  		}
    88  		for i := 0; i < res.objType.NumMethod(); i++ {
    89  			method := res.objType.Method(i)
    90  			res.methodNames = append(res.methodNames, method.Name)
    91  			metadata := newObjMethodMetadata(method.Name, res)
    92  			res.methods[method.Name] = metadata
    93  			res.methods[strings.ToLower(method.Name)] = metadata
    94  		}
    95  	}
    96  
    97  	return res
    98  }
    99  
   100  // IsStructOrPtrToStruct checks if the value is a struct or a pointer to a struct.
   101  func (om *ObjMetadata) IsStructOrPtrToStruct() bool {
   102  	return om.isStruct || om.isPtrToStruct
   103  }
   104  
   105  func (om *ObjMetadata) appendFields(fields []string, field reflect.StructField, listingType fieldListingType) []string {
   106  	if k := field.Type.Kind(); listingType == fieldsAnonymous {
   107  		if field.Anonymous {
   108  			fields = append(fields, field.Name)
   109  		}
   110  	} else if listingType == fieldsAll {
   111  		fields = append(fields, field.Name)
   112  		if k == reflect.Struct && field.Anonymous {
   113  			fields = append(fields, om.getFields(field.Type, listingType)...)
   114  		}
   115  	} else if listingType == fieldsFlattenAnonymous && k == reflect.Struct && field.Anonymous {
   116  		fields = append(fields, om.getFields(field.Type, listingType)...)
   117  	} else {
   118  		fields = append(fields, field.Name)
   119  	}
   120  	return fields
   121  }
   122  
   123  func (om *ObjMetadata) getFields(ty reflect.Type, listingType fieldListingType) []string {
   124  	var fields []string
   125  
   126  	if ty.Kind() == reflect.Ptr {
   127  		ty = ty.Elem()
   128  	}
   129  
   130  	if ty.Kind() != reflect.Struct {
   131  		return fields // No need to populate nonstructs
   132  	}
   133  
   134  	for i := 0; i < ty.NumField(); i++ {
   135  		f := ty.Field(i)
   136  		fields = om.appendFields(fields, f, listingType)
   137  	}
   138  
   139  	return fields
   140  }
   141  
   142  // ObjFieldMetadata contains data which is always unique per Type/Field.
   143  type ObjFieldMetadata struct {
   144  	name string
   145  
   146  	structField reflect.StructField
   147  
   148  	// Valid here is not yet the final info about an actual field validity,
   149  	// because value field still have .IsValid()
   150  	valid bool
   151  
   152  	fieldKind reflect.Kind
   153  	fieldType reflect.Type
   154  }
   155  
   156  func newObjFieldMetadata(name string, objMetadata *ObjMetadata) *ObjFieldMetadata {
   157  	res := &ObjFieldMetadata{}
   158  	res.fieldKind = reflect.Invalid
   159  	res.name = name
   160  	if objMetadata.IsStructOrPtrToStruct() {
   161  		var found bool
   162  		var structField reflect.StructField
   163  		if objMetadata.isPtrToStruct {
   164  			structField, found = objMetadata.objType.Elem().FieldByName(res.name)
   165  		} else {
   166  			structField, found = objMetadata.objType.FieldByName(res.name)
   167  		}
   168  		res.structField = structField
   169  		res.fieldType = structField.Type
   170  		if res.fieldType == nil {
   171  			res.valid = false
   172  		} else {
   173  			res.fieldKind = structField.Type.Kind()
   174  			res.valid = found
   175  		}
   176  	}
   177  	return res
   178  }
   179  
   180  // ObjMethodMetadata contains data
   181  // which is always unique per Type/Method.
   182  type ObjMethodMetadata struct {
   183  	name   string
   184  	method reflect.Method
   185  	valid  bool
   186  }
   187  
   188  func newObjMethodMetadata(name string, objMetadata *ObjMetadata) *ObjMethodMetadata {
   189  	res := &ObjMethodMetadata{name: name}
   190  
   191  	if objMetadata.objKind == reflect.Invalid {
   192  		res.valid = false
   193  	} else {
   194  		if method, found := objMetadata.objType.MethodByName(name); found {
   195  			res.method = method
   196  			res.valid = res.method.Func.IsValid()
   197  		} else {
   198  			res.valid = false
   199  		}
   200  	}
   201  
   202  	return res
   203  }
   204  
   205  // Obj is a wrapper for golang values which need to be reflected.
   206  // The value can be of any kind and any type.
   207  type Obj struct {
   208  	iface interface{}
   209  	// Value used to work with fields. The only special case is when iface is a pointer to a struct, in
   210  	// that case this is the value of that struct:
   211  	fieldsValue reflect.Value
   212  	*ObjMetadata
   213  }
   214  
   215  // NewFromType creates a new Obj but using reflect.Type.
   216  func NewFromType(ty reflect.Type) *Obj {
   217  	if ty == nil {
   218  		return New(nil)
   219  	}
   220  	return New(reflect.New(ty).Interface())
   221  }
   222  
   223  // New initializes a new Obj wrapper.
   224  func New(obj interface{}) *Obj {
   225  	o := &Obj{iface: obj}
   226  
   227  	ty := reflect.TypeOf(obj)
   228  	metadataCacheMutex.RLock()
   229  	metadata, found := metadataCache[ty]
   230  	metadataCacheMutex.RUnlock()
   231  	if found {
   232  		o.ObjMetadata = metadata
   233  	} else {
   234  		o.ObjMetadata = newObjMetadata(reflect.TypeOf(obj))
   235  		updateCache(ty, o)
   236  	}
   237  
   238  	o.fieldsValue = reflect.Indirect(reflect.ValueOf(obj))
   239  
   240  	return o
   241  }
   242  
   243  // IsValid checks if the underlying objects is valid.
   244  // Nil is an invalid value, for example.
   245  func (o *Obj) IsValid() bool { return o.objKind != reflect.Invalid }
   246  
   247  // Len returns object length. Works for arrays, channels, maps, slices and strings.
   248  //
   249  // It doesn't panic for other types, returns 0 instead.
   250  //
   251  // In case the value is a pointer, len checks the underlying value.
   252  func (o *Obj) Len() int {
   253  	switch o.fieldsValue.Kind() {
   254  	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
   255  		return o.fieldsValue.Len()
   256  	}
   257  	return 0
   258  }
   259  
   260  // IsGettableByIndex returns true if underlying type is array, slice or string
   261  func (o *Obj) IsGettableByIndex() bool {
   262  	switch o.fieldsValue.Kind() {
   263  	case reflect.Array, reflect.Slice, reflect.String:
   264  		return true
   265  	default:
   266  		return false
   267  	}
   268  }
   269  
   270  // IsSettableByIndex returns true if underlying type is array, slice (but not string, since they are immutable)
   271  func (o *Obj) IsSettableByIndex() bool {
   272  	switch o.fieldsValue.Kind() {
   273  	case reflect.Array, reflect.Slice:
   274  		return true
   275  	default:
   276  		return false
   277  	}
   278  }
   279  
   280  // IsMap returns true if underlying type is map or a pointer to a map
   281  func (o *Obj) IsMap() bool {
   282  	switch o.fieldsValue.Kind() {
   283  	case reflect.Map:
   284  		return true
   285  	default:
   286  		return false
   287  	}
   288  }
   289  
   290  // GetByIndex returns a value by int index.
   291  //
   292  // Works for arrays, slices and strins. Won't panic when index or kind is invalid.
   293  func (o *Obj) GetByIndex(index int) (value interface{}, found bool) {
   294  	defer func() {
   295  		if err := recover(); err != nil {
   296  			value = nil
   297  			found = false
   298  		}
   299  	}()
   300  
   301  	if o.IsGettableByIndex() {
   302  		if 0 <= index && index < o.fieldsValue.Len() {
   303  			value = o.fieldsValue.Index(index).Interface()
   304  			found = true
   305  			return
   306  		}
   307  	}
   308  
   309  	return
   310  }
   311  
   312  // SetByIndex sets a slice value by key.
   313  func (o *Obj) SetByIndex(index int, val interface{}) error {
   314  	if index < 0 || o.Len() <= index {
   315  		return fmt.Errorf("cannot set element %d", index)
   316  	}
   317  
   318  	if o.IsSettableByIndex() {
   319  		elem := o.fieldsValue.Index(index)
   320  		elem.Set(reflect.ValueOf(val))
   321  		return nil
   322  	}
   323  
   324  	return fmt.Errorf("cannot set element %d of %s", index, o.fieldsValue.String())
   325  }
   326  
   327  // Keys return map keys in unspecified order.
   328  func (o *Obj) Keys() ([]interface{}, error) {
   329  	if o.IsMap() {
   330  		keys := o.fieldsValue.MapKeys()
   331  		res := make([]interface{}, len(keys))
   332  		for n := range keys {
   333  			res[n] = keys[n].Interface()
   334  		}
   335  		return res, nil
   336  	}
   337  	return nil, fmt.Errorf("invalid type %s", o.Type().String())
   338  }
   339  
   340  // SetByKey sets a map value by key.
   341  func (o *Obj) SetByKey(key interface{}, val interface{}) (err error) {
   342  	defer func() {
   343  		if e := recover(); e != nil {
   344  			err = fmt.Errorf("cannot set key %s: %v", key, e)
   345  		}
   346  	}()
   347  
   348  	if o.IsMap() {
   349  		o.fieldsValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(val))
   350  		return
   351  	}
   352  	err = fmt.Errorf("cannot set key %s: %w", key, err)
   353  	return
   354  }
   355  
   356  // GetByKey returns a value by map key.
   357  //
   358  // Won't panic when key is invalid or kind is not map.
   359  func (o *Obj) GetByKey(key interface{}) (value interface{}, found bool) {
   360  	defer func() {
   361  		if err := recover(); err != nil {
   362  			value = nil
   363  			found = false
   364  		}
   365  	}()
   366  
   367  	if o.IsMap() {
   368  		v := o.fieldsValue.MapIndex(reflect.ValueOf(key))
   369  		if !v.IsValid() {
   370  			found = false
   371  			return
   372  		}
   373  		value = v.Interface()
   374  		found = true
   375  		return
   376  	}
   377  	return
   378  }
   379  
   380  // Fields returns fields.
   381  // Don't list fields inside Anonymous fields as distinct fields.
   382  func (o *Obj) Fields() []ObjField { return o.getFields(fieldsNoFlattenAnonymous) }
   383  
   384  // FieldsFlattened returns fields.
   385  // Will not list Anonymous fields but it will list fields declared in those anonymous fields.
   386  func (o Obj) FieldsFlattened() []ObjField { return o.getFields(fieldsFlattenAnonymous) }
   387  
   388  // FieldsAll returns fields.
   389  // List both anonymous fields and fields declared inside anonymous fields.
   390  func (o Obj) FieldsAll() []ObjField { return o.getFields(fieldsAll) }
   391  
   392  // FieldsAnonymous returns only anonymous fields.
   393  func (o Obj) FieldsAnonymous() []ObjField { return o.getFields(fieldsAnonymous) }
   394  
   395  func (o *Obj) getFields(listingType fieldListingType) []ObjField {
   396  	var fieldNames []string
   397  	switch listingType {
   398  	case fieldsAll:
   399  		fieldNames = o.fieldNamesAll
   400  	case fieldsAnonymous:
   401  		fieldNames = o.fieldNamesAnonymous
   402  	case fieldsFlattenAnonymous:
   403  		fieldNames = o.fieldNamesFlattenAnonymous
   404  	case fieldsNoFlattenAnonymous:
   405  		fieldNames = o.fieldNamesNoFlattenAnonymous
   406  	default:
   407  		panic(fmt.Sprintf("Invalid field listing type %d", listingType))
   408  	}
   409  
   410  	res := make([]ObjField, len(fieldNames))
   411  	for n, fieldName := range fieldNames {
   412  		res[n] = *o.Field(fieldName)
   413  	}
   414  
   415  	return res
   416  }
   417  
   418  // FindDoubleFields checks if this object has declared
   419  // multiple fields with a same name.
   420  // (by checking recursively Anonymous fields and their fields)
   421  func (o Obj) FindDoubleFields() []string {
   422  	fields := map[string]int{}
   423  	var res []string
   424  	for _, f := range o.FieldsAll() {
   425  		counter := fields[f.name]
   426  		if counter == 1 {
   427  			res = append(res, f.name)
   428  		}
   429  		fields[f.name] = counter + 1
   430  	}
   431  	return res
   432  }
   433  
   434  // IsPtr checks if the value is a pointer.
   435  func (o Obj) IsPtr() bool { return o.objKind == reflect.Ptr }
   436  
   437  // FieldByTag get a field by tag=value.
   438  // Note that the field name can be invalid.
   439  // You can check the field validity using ObjField.IsValid().
   440  func (o *Obj) FieldByTag(tag, fieldName string) *ObjField {
   441  	for _, v := range o.fields {
   442  		if v.structField.Tag.Get(tag) == fieldName {
   443  			return newObjField(o, v)
   444  		}
   445  	}
   446  
   447  	return newObjField(o, &ObjFieldMetadata{name: fieldName, valid: false, fieldKind: reflect.Invalid})
   448  }
   449  
   450  // Field get a field wrapper.
   451  // Note that the field name can be invalid.
   452  // You can check the field validity using ObjField.IsValid().
   453  func (o *Obj) Field(fieldName string) *ObjField {
   454  	if o.fieldsValue.IsValid() {
   455  		if metadata, found := o.fields[fieldName]; found {
   456  			return newObjField(o, metadata)
   457  		}
   458  	}
   459  	return newObjField(o, &ObjFieldMetadata{name: fieldName, valid: false, fieldKind: reflect.Invalid})
   460  }
   461  
   462  // Type returns the value type.
   463  // If kind is invalid, this will return a zero filled reflect.Type.
   464  func (o Obj) Type() reflect.Type { return o.objType }
   465  
   466  // Kind returns the value's kind.
   467  func (o Obj) Kind() reflect.Kind { return o.objKind }
   468  
   469  func (o Obj) String() string {
   470  	if o.objType == nil {
   471  		return "nil"
   472  	}
   473  	return o.objType.String()
   474  }
   475  
   476  // Method returns a new method wrapper.
   477  // The method name can be invalid, check the method validity with ObjMethod.IsValid().
   478  func (o *Obj) Method(name string) *ObjMethod {
   479  	if metadata, found := o.methods[name]; found {
   480  		return newObjMethod(o, metadata)
   481  	}
   482  	return newObjMethod(o, &ObjMethodMetadata{name: name, valid: false})
   483  }
   484  
   485  // Methods returns the list of all methods.
   486  func (o *Obj) Methods() []ObjMethod {
   487  	res := make([]ObjMethod, 0, len(o.methodNames))
   488  	for _, name := range o.methodNames {
   489  		res = append(res, *o.Method(name))
   490  	}
   491  	return res
   492  }
   493  
   494  // ObjField is a wrapper for the object's field.
   495  type ObjField struct {
   496  	obj   *Obj
   497  	value reflect.Value
   498  
   499  	*ObjFieldMetadata
   500  }
   501  
   502  func newObjField(obj *Obj, metadata *ObjFieldMetadata) *ObjField {
   503  	res := &ObjField{
   504  		obj:              obj,
   505  		ObjFieldMetadata: metadata,
   506  	}
   507  
   508  	if metadata.valid && res.obj.IsStructOrPtrToStruct() {
   509  		res.value = obj.fieldsValue.FieldByName(res.name)
   510  	}
   511  
   512  	return res
   513  }
   514  
   515  func (of *ObjField) assertValid() error {
   516  	if !of.IsValid() {
   517  		return fmt.Errorf("invalid field %s", of.name)
   518  	}
   519  	return nil
   520  }
   521  
   522  // IsValid checks if the fields is valid.
   523  func (of *ObjField) IsValid() bool { return of.valid && of.value.IsValid() }
   524  
   525  // Name returns the field's name.
   526  func (of *ObjField) Name() string { return of.name }
   527  
   528  // Kind returns the field's kind.
   529  func (of *ObjField) Kind() reflect.Kind { return of.fieldKind }
   530  
   531  // Type returns the field's type.
   532  func (of *ObjField) Type() reflect.Type { return of.fieldType }
   533  
   534  // Tag returns the value of this specific tag
   535  // or error if the field is invalid.
   536  func (of *ObjField) Tag(tag string) (string, error) {
   537  	if err := of.assertValid(); err != nil {
   538  		return "", err
   539  	}
   540  	return of.structField.Tag.Get(tag), nil
   541  }
   542  
   543  // Tags returns the map of all fields or error for invalid field.
   544  func (of *ObjField) Tags() (Tags, error) {
   545  	if err := of.assertValid(); err != nil {
   546  		return nil, err
   547  	}
   548  
   549  	tag := of.structField.Tag
   550  	return ParseTags(string(tag))
   551  }
   552  
   553  // TagExpanded returns the tag value "expanded" with commas.
   554  func (of *ObjField) TagExpanded(tag string) ([]string, error) {
   555  	if err := of.assertValid(); err != nil {
   556  		return nil, err
   557  	}
   558  	return strings.Split(of.structField.Tag.Get(tag), ","), nil
   559  }
   560  
   561  // IsAnonymous checks if this is an anonymous (embedded) field.
   562  func (of *ObjField) IsAnonymous() bool {
   563  	if err := of.assertValid(); err != nil {
   564  		return false
   565  	}
   566  	field, found := of.obj.underlyingType.FieldByName(of.name)
   567  	return found && field.Anonymous
   568  }
   569  
   570  // IsExported returns true if the name starts with uppercase (i.e. field is public).
   571  func (of *ObjField) IsExported() bool { return of.structField.PkgPath == "" }
   572  
   573  // IsSettable checks if this field is settable.
   574  func (of *ObjField) IsSettable() bool { return of.value.CanSet() }
   575  
   576  // Set sets a value for this field or error if field is invalid (or not settable).
   577  func (of *ObjField) Set(value interface{}) error {
   578  	if err := of.assertValid(); err != nil {
   579  		return err
   580  	}
   581  
   582  	if !of.IsSettable() {
   583  		return fmt.Errorf("field %s in %T not settable", of.name, of.obj.iface)
   584  	}
   585  
   586  	of.value.Set(reflect.ValueOf(value))
   587  
   588  	return nil
   589  }
   590  
   591  // Get gets the field value of error if field is invalid).
   592  func (of *ObjField) Get() (interface{}, error) {
   593  	if err := of.assertValid(); err != nil {
   594  		return nil, err
   595  	}
   596  	if !of.IsExported() {
   597  		return nil, fmt.Errorf("cannot read unexported field %T.%s", of.obj.iface, of.name)
   598  	}
   599  
   600  	return of.value.Interface(), nil
   601  }
   602  
   603  // ObjMethod is a wrapper for an object method.
   604  // The name of the method can be invalid.
   605  type ObjMethod struct {
   606  	obj *Obj
   607  	*ObjMethodMetadata
   608  }
   609  
   610  func newObjMethod(obj *Obj, objMethodMetadata *ObjMethodMetadata) *ObjMethod {
   611  	return &ObjMethod{
   612  		obj:               obj,
   613  		ObjMethodMetadata: objMethodMetadata,
   614  	}
   615  }
   616  
   617  // Name returns the method's name.
   618  func (om *ObjMethod) Name() string { return om.name }
   619  
   620  const (
   621  	onlyInTypes  = 0
   622  	onlyOutTypes = 1
   623  )
   624  
   625  func (om *ObjMethod) methodTypes(kind int) []reflect.Type {
   626  	m := reflect.ValueOf(om.obj.iface).MethodByName(om.name)
   627  	if !m.IsValid() {
   628  		return []reflect.Type{}
   629  	}
   630  	ty := m.Type()
   631  
   632  	// inTypes are default
   633  	tyNum := ty.NumIn()
   634  	tyFn := ty.In
   635  	if kind == onlyOutTypes {
   636  		tyNum = ty.NumOut()
   637  		tyFn = ty.Out
   638  	}
   639  
   640  	out := make([]reflect.Type, tyNum)
   641  	for i := 0; i < tyNum; i++ {
   642  		out[i] = tyFn(i)
   643  	}
   644  	return out
   645  }
   646  
   647  // InTypes returns a slice with this method's input types.
   648  func (om *ObjMethod) InTypes() []reflect.Type { return om.methodTypes(onlyInTypes) }
   649  
   650  // OutTypes returns a slice with this method's output types.
   651  func (om *ObjMethod) OutTypes() []reflect.Type { return om.methodTypes(onlyOutTypes) }
   652  
   653  // IsValid returns this method's validity.
   654  func (om *ObjMethod) IsValid() bool { return om.valid }
   655  
   656  // Call calls this method.
   657  // Note that in the error returning value is not the error from the method call.
   658  func (om *ObjMethod) Call(args ...interface{}) (*CallResult, error) {
   659  	if !om.obj.IsValid() {
   660  		return nil, fmt.Errorf("invalid object type %T for method %s", om.obj.iface, om.name)
   661  	}
   662  	if !om.IsValid() {
   663  		return nil, fmt.Errorf("invalid method %s in %T", om.name, om.obj.iface)
   664  	}
   665  	in := make([]reflect.Value, len(args)+1)
   666  	in[0] = reflect.ValueOf(om.obj.iface)
   667  	for n := range args {
   668  		in[n+1] = reflect.ValueOf(args[n])
   669  	}
   670  	out := om.method.Func.Call(in)
   671  	res := make([]interface{}, len(out))
   672  	for n := range out {
   673  		res[n] = out[n].Interface()
   674  	}
   675  	return newCallResult(res), nil
   676  }
   677  
   678  // CallResult is a wrapper of a method call result.
   679  type CallResult struct {
   680  	Result []interface{}
   681  	Error  error
   682  }
   683  
   684  func newCallResult(res []interface{}) *CallResult {
   685  	cr := &CallResult{Result: res}
   686  	if len(res) == 0 {
   687  		return cr
   688  	}
   689  	errorCandidate := res[len(res)-1]
   690  	if errorCandidate != nil {
   691  		if err, is := errorCandidate.(error); is {
   692  			cr.Error = err
   693  		}
   694  	}
   695  	return cr
   696  }
   697  
   698  // IsError checks if the last value is a non-nil error.
   699  func (cr *CallResult) IsError() bool { return cr.Error != nil }