github.com/anchore/syft@v1.38.2/internal/cache/hash_type.go (about)

     1  package cache
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  
     7  	"github.com/gohugoio/hashstructure"
     8  )
     9  
    10  // hashType returns a stable hash based on the structure of the type
    11  func hashType[T any]() string {
    12  	// get the base type and hash an empty instance
    13  	var t T
    14  	empty := emptyValue(reflect.TypeOf(t)).Interface()
    15  	hash, err := hashstructure.Hash(empty, &hashstructure.HashOptions{
    16  		ZeroNil:         false,
    17  		IgnoreZeroValue: false,
    18  		SlicesAsSets:    false,
    19  		UseStringer:     false,
    20  	})
    21  	if err != nil {
    22  		panic(fmt.Errorf("unable to use type as cache key: %w", err))
    23  	}
    24  	return fmt.Sprintf("%x", hash)
    25  }
    26  
    27  func emptyValue(t reflect.Type) reflect.Value {
    28  	switch t.Kind() {
    29  	case reflect.Pointer:
    30  		e := t.Elem()
    31  		v := emptyValue(e)
    32  		if v.CanAddr() {
    33  			return v.Addr()
    34  		}
    35  		ptrv := reflect.New(e)
    36  		ptrv.Elem().Set(v)
    37  		return ptrv
    38  	case reflect.Slice:
    39  		v := emptyValue(t.Elem())
    40  		s := reflect.MakeSlice(t, 1, 1)
    41  		s.Index(0).Set(v)
    42  		return s
    43  	case reflect.Struct:
    44  		v := reflect.New(t).Elem()
    45  		// get all empty field values, too
    46  		for i := 0; i < v.NumField(); i++ {
    47  			f := t.Field(i)
    48  			if isIgnored(f) {
    49  				continue
    50  			}
    51  			fv := v.Field(i)
    52  			if fv.CanSet() {
    53  				fv.Set(emptyValue(f.Type))
    54  			}
    55  		}
    56  		return v
    57  	default:
    58  		return reflect.New(t).Elem()
    59  	}
    60  }
    61  
    62  func isIgnored(f reflect.StructField) bool {
    63  	if !f.IsExported() {
    64  		return true
    65  	}
    66  	tag := f.Tag.Get("hash")
    67  	if tag == "-" || tag == "ignore" {
    68  		return true
    69  	}
    70  	return false
    71  }