github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/vals/equal.go (about)

     1  package vals
     2  
     3  import (
     4  	"math/big"
     5  	"reflect"
     6  )
     7  
     8  // Equaler wraps the Equal method.
     9  type Equaler interface {
    10  	// Equal compares the receiver to another value. Two equal values must have
    11  	// the same hash code.
    12  	Equal(other interface{}) bool
    13  }
    14  
    15  // Equal returns whether two values are equal. It is implemented for the builtin
    16  // types bool and string, the File, List, Map types, StructMap types, and types
    17  // satisfying the Equaler interface. For other types, it uses reflect.DeepEqual
    18  // to compare the two values.
    19  func Equal(x, y interface{}) bool {
    20  	switch x := x.(type) {
    21  	case nil:
    22  		return x == y
    23  	case bool:
    24  		return x == y
    25  	case int:
    26  		return x == y
    27  	case float64:
    28  		return x == y
    29  	case *big.Int:
    30  		if y, ok := y.(*big.Int); ok {
    31  			return x.Cmp(y) == 0
    32  		}
    33  		return false
    34  	case *big.Rat:
    35  		if y, ok := y.(*big.Rat); ok {
    36  			return x.Cmp(y) == 0
    37  		}
    38  		return false
    39  	case string:
    40  		return x == y
    41  	case Equaler:
    42  		return x.Equal(y)
    43  	case File:
    44  		if yy, ok := y.(File); ok {
    45  			return x.Fd() == yy.Fd()
    46  		}
    47  		return false
    48  	case List:
    49  		if yy, ok := y.(List); ok {
    50  			return equalList(x, yy)
    51  		}
    52  		return false
    53  	case Map:
    54  		if yy, ok := y.(Map); ok {
    55  			return equalMap(x, yy)
    56  		}
    57  		return false
    58  	case StructMap:
    59  		if yy, ok := y.(StructMap); ok {
    60  			return equalStructMap(x, yy)
    61  		}
    62  		return false
    63  	default:
    64  		return reflect.DeepEqual(x, y)
    65  	}
    66  }
    67  
    68  func equalList(x, y List) bool {
    69  	if x.Len() != y.Len() {
    70  		return false
    71  	}
    72  	ix := x.Iterator()
    73  	iy := y.Iterator()
    74  	for ix.HasElem() && iy.HasElem() {
    75  		if !Equal(ix.Elem(), iy.Elem()) {
    76  			return false
    77  		}
    78  		ix.Next()
    79  		iy.Next()
    80  	}
    81  	return true
    82  }
    83  
    84  func equalMap(x, y Map) bool {
    85  	if x.Len() != y.Len() {
    86  		return false
    87  	}
    88  	for it := x.Iterator(); it.HasElem(); it.Next() {
    89  		k, vx := it.Elem()
    90  		vy, ok := y.Index(k)
    91  		if !ok || !Equal(vx, vy) {
    92  			return false
    93  		}
    94  	}
    95  	return true
    96  }
    97  
    98  func equalStructMap(x, y StructMap) bool {
    99  	t := reflect.TypeOf(x)
   100  	if t != reflect.TypeOf(y) {
   101  		return false
   102  	}
   103  
   104  	xValue := reflect.ValueOf(x)
   105  	yValue := reflect.ValueOf(y)
   106  	it := iterateStructMap(t)
   107  	for it.Next() {
   108  		_, xField := it.Get(xValue)
   109  		_, yField := it.Get(yValue)
   110  		if !Equal(xField, yField) {
   111  			return false
   112  		}
   113  	}
   114  	return true
   115  }