mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-04 10:57:50 +08:00
96752afa4d
Struct map is a mechanism to let Go code expose simple structs to Elvish code. The difference between struct maps and maps is convenience for Go code; they also have different performance characteristics, but since struct maps are always quite small, the difference is not meaningful for Elvish's use cases. As a result, there is no good reason that Elvish code needs to be aware of the difference between struct maps and normal maps. Making them indistinguishable to Elvish code simplifies the language. This commit does the following: - Change Equal, Hash, Kind and Repr to treat struct maps like maps. - Change Assoc and Dissoc to "promote" struct maps to maps. - Remove the custom Repr method of parse.Source. - Update documentation to reflect this change.
107 lines
2.2 KiB
Go
107 lines
2.2 KiB
Go
package vals
|
|
|
|
import (
|
|
"math/big"
|
|
"reflect"
|
|
|
|
"src.elv.sh/pkg/persistent/hashmap"
|
|
)
|
|
|
|
// Equaler wraps the Equal method.
|
|
type Equaler interface {
|
|
// Equal compares the receiver to another value. Two equal values must have
|
|
// the same hash code.
|
|
Equal(other any) bool
|
|
}
|
|
|
|
// Equal returns whether two values are equal. It is implemented for the builtin
|
|
// types bool and string, the File, List, Map types, StructMap types, and types
|
|
// satisfying the Equaler interface. For other types, it uses reflect.DeepEqual
|
|
// to compare the two values.
|
|
func Equal(x, y any) bool {
|
|
switch x := x.(type) {
|
|
case nil:
|
|
return x == y
|
|
case bool:
|
|
return x == y
|
|
case int:
|
|
return x == y
|
|
case *big.Int:
|
|
if y, ok := y.(*big.Int); ok {
|
|
return x.Cmp(y) == 0
|
|
}
|
|
return false
|
|
case *big.Rat:
|
|
if y, ok := y.(*big.Rat); ok {
|
|
return x.Cmp(y) == 0
|
|
}
|
|
return false
|
|
case float64:
|
|
return x == y
|
|
case string:
|
|
return x == y
|
|
case List:
|
|
if yy, ok := y.(List); ok {
|
|
return equalList(x, yy)
|
|
}
|
|
return false
|
|
// Types above are also handled in [Cmp]; keep the branches in the same
|
|
// order.
|
|
case Equaler:
|
|
return x.Equal(y)
|
|
case File:
|
|
if yy, ok := y.(File); ok {
|
|
return x.Fd() == yy.Fd()
|
|
}
|
|
return false
|
|
case Map:
|
|
switch y := y.(type) {
|
|
case Map:
|
|
return equalMap(x, y, Map.Iterator, Map.Index)
|
|
case StructMap:
|
|
return equalMap(x, y, Map.Iterator, indexStructMap)
|
|
}
|
|
return false
|
|
case StructMap:
|
|
switch y := y.(type) {
|
|
case Map:
|
|
return equalMap(x, y, iterateStructMap, Map.Index)
|
|
case StructMap:
|
|
return equalMap(x, y, iterateStructMap, indexStructMap)
|
|
}
|
|
return false
|
|
default:
|
|
return reflect.DeepEqual(x, y)
|
|
}
|
|
}
|
|
|
|
func equalList(x, y List) bool {
|
|
if x.Len() != y.Len() {
|
|
return false
|
|
}
|
|
ix := x.Iterator()
|
|
iy := y.Iterator()
|
|
for ix.HasElem() && iy.HasElem() {
|
|
if !Equal(ix.Elem(), iy.Elem()) {
|
|
return false
|
|
}
|
|
ix.Next()
|
|
iy.Next()
|
|
}
|
|
return true
|
|
}
|
|
|
|
func equalMap[X, Y any, I hashmap.Iterator](x X, y Y, xit func(X) I, yidx func(Y, any) (any, bool)) bool {
|
|
if Len(x) != Len(y) {
|
|
return false
|
|
}
|
|
for it := xit(x); it.HasElem(); it.Next() {
|
|
k, vx := it.Elem()
|
|
vy, ok := yidx(y, k)
|
|
if !ok || !Equal(vx, vy) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|