github.com/ipld/go-ipld-prime@v0.21.0/datamodel/equal.go (about) 1 package datamodel 2 3 // DeepEqual reports whether x and y are "deeply equal" as IPLD nodes. 4 // This is similar to reflect.DeepEqual, but based around the Node interface. 5 // 6 // Two nodes must have the same kind to be deeply equal. 7 // If either node has the invalid kind, the nodes are not deeply equal. 8 // 9 // Two nodes of scalar kinds (null, bool, int, float, string, bytes, link) 10 // are deeply equal if their Go values, as returned by AsKind methods, are equal as 11 // per Go's == comparison operator. 12 // 13 // Note that Links are compared in a shallow way, without being followed. 14 // This will generally be enough, as it's rare to have two different links to the 15 // same IPLD data by using a different codec or multihash type. 16 // 17 // Two nodes of recursive kinds (map, list) 18 // must have the same length to be deeply equal. 19 // Their elements, as reported by iterators, must be deeply equal. 20 // The elements are compared in the iterator's order, 21 // meaning two maps sorting the same keys differently might not be equal. 22 // 23 // Note that this function panics if either Node returns an error. 24 // We only call valid methods for each Kind, 25 // so an error should only happen if a Node implementation breaks that contract. 26 // It is generally not recommended to call DeepEqual on ADL nodes. 27 func DeepEqual(x, y Node) bool { 28 if x == nil || y == nil { 29 return x == y 30 } 31 xk, yk := x.Kind(), y.Kind() 32 if xk != yk { 33 return false 34 } 35 36 switch xk { 37 38 // Scalar kinds. 39 case Kind_Null: 40 return x.IsNull() == y.IsNull() 41 case Kind_Bool: 42 xv, err := x.AsBool() 43 if err != nil { 44 panic(err) 45 } 46 yv, err := y.AsBool() 47 if err != nil { 48 panic(err) 49 } 50 return xv == yv 51 case Kind_Int: 52 xv, err := x.AsInt() 53 if err != nil { 54 panic(err) 55 } 56 yv, err := y.AsInt() 57 if err != nil { 58 panic(err) 59 } 60 return xv == yv 61 case Kind_Float: 62 xv, err := x.AsFloat() 63 if err != nil { 64 panic(err) 65 } 66 yv, err := y.AsFloat() 67 if err != nil { 68 panic(err) 69 } 70 return xv == yv 71 case Kind_String: 72 xv, err := x.AsString() 73 if err != nil { 74 panic(err) 75 } 76 yv, err := y.AsString() 77 if err != nil { 78 panic(err) 79 } 80 return xv == yv 81 case Kind_Bytes: 82 xv, err := x.AsBytes() 83 if err != nil { 84 panic(err) 85 } 86 yv, err := y.AsBytes() 87 if err != nil { 88 panic(err) 89 } 90 return string(xv) == string(yv) 91 case Kind_Link: 92 xv, err := x.AsLink() 93 if err != nil { 94 panic(err) 95 } 96 yv, err := y.AsLink() 97 if err != nil { 98 panic(err) 99 } 100 // Links are just compared via ==. 101 // This requires the types to exactly match, 102 // and the values to be equal as per == too. 103 // This will generally work, 104 // as ipld-prime assumes link types to be consistent. 105 return xv == yv 106 107 // Recursive kinds. 108 case Kind_Map: 109 if x.Length() != y.Length() { 110 return false 111 } 112 xitr := x.MapIterator() 113 yitr := y.MapIterator() 114 for !xitr.Done() && !yitr.Done() { 115 xkey, xval, err := xitr.Next() 116 if err != nil { 117 panic(err) 118 } 119 ykey, yval, err := yitr.Next() 120 if err != nil { 121 panic(err) 122 } 123 if !DeepEqual(xkey, ykey) { 124 return false 125 } 126 if !DeepEqual(xval, yval) { 127 return false 128 } 129 } 130 return true 131 case Kind_List: 132 if x.Length() != y.Length() { 133 return false 134 } 135 xitr := x.ListIterator() 136 yitr := y.ListIterator() 137 for !xitr.Done() && !yitr.Done() { 138 _, xval, err := xitr.Next() 139 if err != nil { 140 panic(err) 141 } 142 _, yval, err := yitr.Next() 143 if err != nil { 144 panic(err) 145 } 146 if !DeepEqual(xval, yval) { 147 return false 148 } 149 } 150 return true 151 152 // As per the docs, other kinds such as Invalid are not deeply equal. 153 default: 154 return false 155 } 156 }