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  }