func()

in pkg/cloud/api/diff.go [119:224]


func (d *differ[T]) do(p Path, av, bv reflect.Value) error {
	// cmpZero applies to pointer, slice and map values. Returns true if no
	// further diff'ing is required for the values.
	cmpZero := func() bool {
		switch {
		case av.IsZero() && bv.IsZero():
			return true
		case !av.IsZero() && bv.IsZero():
			d.result.add(DiffItemOnlyInA, p, av, bv)
			return true
		case av.IsZero() && !bv.IsZero():
			d.result.add(DiffItemOnlyInB, p, av, bv)
			return true
		}
		return false
	}

	switch {
	case isBasicV(av):
		if !av.Equal(bv) {
			d.result.add(DiffItemDifferent, p, av, bv)
		}
		return nil

	case av.Type().Kind() == reflect.Pointer:
		if cmpZero() {
			return nil
		}
		return d.do(p.Pointer(), av.Elem(), bv.Elem())

	case av.Type().Kind() == reflect.Struct:
		for i := 0; i < av.NumField(); i++ {
			afv := av.Field(i)
			aft := av.Type().Field(i)

			if aft.Name == "NullFields" || aft.Name == "ForceSendFields" {
				continue
			}

			fp := p.Field(aft.Name)
			switch d.traits.FieldType(fp) {
			case FieldTypeOutputOnly, FieldTypeSystem:
				continue
			}

			bfv := bv.FieldByName(aft.Name)
			if !bfv.IsValid() {
				d.result.add(DiffItemOnlyInA, p, av, bv)
				continue
			}
			if err := d.do(fp, afv, bfv); err != nil {
				return fmt.Errorf("differ struct %p: %w", fp, err)
			}
		}
		return nil

	case av.Type().Kind() == reflect.Slice:
		if cmpZero() {
			return nil
		}
		// If we find the list lengths are difference, don't recurse into a list
		// to compare item by item. There isn't a use case for a more fine grain
		// diff within a slice at the moment.
		if av.Len() != bv.Len() {
			d.result.add(DiffItemDifferent, p, av, bv)
			return nil
		}
		for i := 0; i < av.Len(); i++ {
			asv := av.Index(i)
			bsv := bv.Index(i)
			sp := p.Index(i)
			if err := d.do(sp, asv, bsv); err != nil {
				return fmt.Errorf("differ slice %p: %w", sp, err)
			}
		}
		return nil

	case av.Type().Kind() == reflect.Map:
		if cmpZero() {
			return nil
		}
		if av.Len() != bv.Len() {
			d.result.add(DiffItemDifferent, p, av, bv)
			return nil
		}
		// For maps of the same size, for the maps to be equal, all keys in A
		// must be present in B for these to be equal. This means we don't have
		// to check  in the opposite direction from B to A. However, this makes
		// the Diff function non-symmetric.
		for _, amk := range av.MapKeys() {
			amv := av.MapIndex(amk)
			bmv := bv.MapIndex(amk)
			mp := p.MapIndex(amk)

			if !bmv.IsValid() {
				d.result.add(DiffItemDifferent, mp, amv, bmv)
			}
			if err := d.do(mp, amv, bmv); err != nil {
				return fmt.Errorf("differ map %p: %w", mp, err)
			}
		}
		return nil
	}

	return fmt.Errorf("differ: invalid type: %s", av.Type())
}