github.com/elves/elvish@v0.15.0/pkg/eval/vals/equal.go (about)

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